Beispiel #1
0
size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
    const uint8_t *key, size_t key_len)
{
  uint8_t *ptr;
  uint32_t fpr;
  int saved_id_idx = 0;
  uint8_t md5[16];

  if (stun_message_get_class (msg) == STUN_REQUEST) {
    for (saved_id_idx = 0; saved_id_idx < STUN_AGENT_MAX_SAVED_IDS; saved_id_idx++) {
      if (agent->sent_ids[saved_id_idx].valid == FALSE) {
        break;
      }
    }
  }
  if (saved_id_idx == STUN_AGENT_MAX_SAVED_IDS) {
    stun_debug ("Saved ids full");
    return 0;
  }

  if (msg->key != NULL) {
    key = msg->key;
    key_len = msg->key_len;
  }

  if (key != NULL) {
    bool skip = FALSE;

    if (msg->long_term_valid) {
      memcpy (md5, msg->long_term_key, sizeof(msg->long_term_key));
    } else if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
      uint8_t *realm = NULL;
      uint8_t *username = NULL;
      uint16_t realm_len;
      uint16_t username_len;

      realm = (uint8_t *) stun_message_find (msg,
          STUN_ATTRIBUTE_REALM, &realm_len);
      username = (uint8_t *) stun_message_find (msg,
          STUN_ATTRIBUTE_USERNAME, &username_len);
      if (username == NULL || realm == NULL) {
        skip = TRUE;
      } else {
        stun_hash_creds (realm, realm_len,
            username,  username_len,
            key, key_len, md5);
      }
      memcpy (msg->long_term_key, md5, sizeof(msg->long_term_key));
      msg->long_term_valid = TRUE;
    }

    /* If no realm/username and long term credentials,
       then don't send the message integrity */
    if (skip == FALSE) {
      ptr = stun_message_append (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, 20);
      if (ptr == NULL) {
        return 0;
      }
      if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
        if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
          stun_sha1 (msg->buffer, stun_message_length (msg),
              stun_message_length (msg) - 20, ptr, md5, sizeof(md5), TRUE);
        } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
          size_t minus = 20;
          if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT)
            minus -= 8;

          stun_sha1 (msg->buffer, stun_message_length (msg),
              stun_message_length (msg) - minus, ptr, md5, sizeof(md5), TRUE);
        } else {
          stun_sha1 (msg->buffer, stun_message_length (msg),
              stun_message_length (msg) - 20, ptr, md5, sizeof(md5), FALSE);
        }
      } else {
        if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
          stun_sha1 (msg->buffer, stun_message_length (msg),
              stun_message_length (msg) - 20, ptr, key, key_len, TRUE);
        } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
          size_t minus = 20;
          if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT)
            minus -= 8;

          stun_sha1 (msg->buffer, stun_message_length (msg),
              stun_message_length (msg) - minus, ptr, key, key_len, TRUE);
        } else {
          stun_sha1 (msg->buffer, stun_message_length (msg),
              stun_message_length (msg) - 20, ptr, key, key_len, FALSE);
        }
      }

      stun_debug (" Message HMAC-SHA1 message integrity:"
          "\n  key     : ");
      stun_debug_bytes (key, key_len);
      stun_debug ("\n  sent    : ");
      stun_debug_bytes (ptr, 20);
      stun_debug ("\n");
    }
  }

  if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
          agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
      agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
    ptr = stun_message_append (msg, STUN_ATTRIBUTE_FINGERPRINT, 4);
    if (ptr == NULL) {
      return 0;
    }

    fpr = stun_fingerprint (msg->buffer, stun_message_length (msg),
        agent->compatibility == STUN_COMPATIBILITY_WLM2009);
    memcpy (ptr, &fpr, sizeof (fpr));

    stun_debug (" Message HMAC-SHA1 fingerprint: ");
    stun_debug_bytes (ptr, 4);
    stun_debug ("\n");
  }


  if (stun_message_get_class (msg) == STUN_REQUEST) {
    stun_message_id (msg, agent->sent_ids[saved_id_idx].id);
    agent->sent_ids[saved_id_idx].method = stun_message_get_method (msg);
    agent->sent_ids[saved_id_idx].key = (uint8_t *) key;
    agent->sent_ids[saved_id_idx].key_len = key_len;
    memcpy (agent->sent_ids[saved_id_idx].long_term_key, msg->long_term_key,
        sizeof(msg->long_term_key));
    agent->sent_ids[saved_id_idx].long_term_valid = msg->long_term_valid;
    agent->sent_ids[saved_id_idx].valid = TRUE;
  }

  msg->key = (uint8_t *) key;
  msg->key_len = key_len;
  return stun_message_length (msg);

}
Beispiel #2
0
size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
    const uint8_t *key, size_t key_len)
{
  uint8_t *ptr;
  uint32_t fpr;
  int saved_id_idx = 0;
  uint8_t md5[16];
  bool remember_transaction;

  remember_transaction = (stun_message_get_class (msg) == STUN_REQUEST);

  if (agent->compatibility == STUN_COMPATIBILITY_OC2007 &&
      stun_message_get_method (msg) == STUN_SEND) {
    /* As per [MS-TURN] Section 2.2.1, the TURN server doesn't send responses to
     * STUN_SEND requests, so don't bother waiting for them. More details at
     * https://msdn.microsoft.com/en-us/library/dd946797%28v=office.12%29.aspx.
     */
    remember_transaction = FALSE;
  }

  if (remember_transaction) {
    for (saved_id_idx = 0; saved_id_idx < STUN_AGENT_MAX_SAVED_IDS; saved_id_idx++) {
      if (agent->sent_ids[saved_id_idx].valid == FALSE) {
        break;
      }
    }
  }
  if (saved_id_idx == STUN_AGENT_MAX_SAVED_IDS) {
    stun_debug ("WARNING: Saved IDs full. STUN message dropped.");
    return 0;
  }

  if (msg->key != NULL) {
    key = msg->key;
    key_len = msg->key_len;
  }

  if (key != NULL) {
    bool skip = FALSE;

    if (msg->long_term_valid) {
      memcpy (md5, msg->long_term_key, sizeof(msg->long_term_key));
    } else if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
      uint8_t *realm = NULL;
      uint8_t *username = NULL;
      uint16_t realm_len;
      uint16_t username_len;

      realm = (uint8_t *) stun_message_find (msg,
          STUN_ATTRIBUTE_REALM, &realm_len);
      username = (uint8_t *) stun_message_find (msg,
          STUN_ATTRIBUTE_USERNAME, &username_len);
      if (username == NULL || realm == NULL) {
        skip = TRUE;
      } else {
        stun_hash_creds (realm, realm_len,
            username,  username_len,
            key, key_len, md5);
        memcpy (msg->long_term_key, md5, sizeof(msg->long_term_key));
        msg->long_term_valid = TRUE;
      }
    }

    /* If no realm/username and long term credentials,
       then don't send the message integrity */
    if (skip == FALSE) {
      ptr = stun_message_append (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, 20);
      if (ptr == NULL) {
        return 0;
      }
      if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
        if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 ||
            agent->compatibility == STUN_COMPATIBILITY_OC2007) {
          stun_sha1 (msg->buffer, stun_message_length (msg),
              stun_message_length (msg) - 20, ptr, md5, sizeof(md5), TRUE);
        } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
          size_t minus = 20;
          if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT)
            minus -= 8;

          stun_sha1 (msg->buffer, stun_message_length (msg),
              stun_message_length (msg) - minus, ptr, md5, sizeof(md5), TRUE);
        } else {
          stun_sha1 (msg->buffer, stun_message_length (msg),
              stun_message_length (msg) - 20, ptr, md5, sizeof(md5), FALSE);
        }
      } else {
        if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 ||
            agent->compatibility == STUN_COMPATIBILITY_OC2007) {
          stun_sha1 (msg->buffer, stun_message_length (msg),
              stun_message_length (msg) - 20, ptr, key, key_len, TRUE);
        } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
          size_t minus = 20;
          if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT)
            minus -= 8;

          stun_sha1 (msg->buffer, stun_message_length (msg),
              stun_message_length (msg) - minus, ptr, key, key_len, TRUE);
        } else {
          stun_sha1 (msg->buffer, stun_message_length (msg),
              stun_message_length (msg) - 20, ptr, key, key_len, FALSE);
        }
      }

      stun_debug (" Message HMAC-SHA1 message integrity:");
      stun_debug_bytes ("  key     : ", key, key_len);
      stun_debug_bytes ("  sent    : ", ptr, 20);
    }
  }

  if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
          agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
      agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
    ptr = stun_message_append (msg, STUN_ATTRIBUTE_FINGERPRINT, 4);
    if (ptr == NULL) {
      return 0;
    }

    fpr = stun_fingerprint (msg->buffer, stun_message_length (msg),
        agent->compatibility == STUN_COMPATIBILITY_WLM2009);
    memcpy (ptr, &fpr, sizeof (fpr));

    stun_debug_bytes (" Message HMAC-SHA1 fingerprint: ", ptr, 4);
  }


  if (remember_transaction) {
    stun_message_id (msg, agent->sent_ids[saved_id_idx].id);
    agent->sent_ids[saved_id_idx].method = stun_message_get_method (msg);
    agent->sent_ids[saved_id_idx].key = (uint8_t *) key;
    agent->sent_ids[saved_id_idx].key_len = key_len;
    memcpy (agent->sent_ids[saved_id_idx].long_term_key, msg->long_term_key,
        sizeof(msg->long_term_key));
    agent->sent_ids[saved_id_idx].long_term_valid = msg->long_term_valid;
    agent->sent_ids[saved_id_idx].valid = TRUE;
  }

  msg->key = (uint8_t *) key;
  msg->key_len = key_len;
  return stun_message_length (msg);

}