Exemplo n.º 1
0
static void validate (const uint8_t *msg, unsigned len)
{
  unsigned i = 1;

  do
  {
    size_t vlen = stun_message_validate_buffer_length (msg, i, TRUE);
    if ((vlen & 3) || (vlen != ((i >= len) * len)))
      fatal ("%u/%u short message test failed", i, len);
  }
  while (i++ < (len + 4));
}
Exemplo n.º 2
0
StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
    const uint8_t *buffer, size_t buffer_len,
    StunMessageIntegrityValidate validater, void * validater_data)
{
  StunTransactionId msg_id;
  uint32_t fpr;
  uint32_t crc32;
  int len;
  uint8_t *username = NULL;
  uint16_t username_len;
  uint8_t *key = NULL;
  size_t key_len;
  uint8_t *hash;
  uint8_t sha[20];
  uint16_t hlen;
  int sent_id_idx = -1;
  uint16_t unknown;
  int error_code;
  int ignore_credentials = 0;
  uint8_t long_term_key[16];
  bool long_term_key_valid = FALSE;

  len = stun_message_validate_buffer_length (buffer, buffer_len);
  if (len == STUN_MESSAGE_BUFFER_INVALID) {
    return STUN_VALIDATION_NOT_STUN;
  } else if (len == STUN_MESSAGE_BUFFER_INCOMPLETE) {
    return STUN_VALIDATION_INCOMPLETE_STUN;
  } else if (len != (int) buffer_len) {
    return STUN_VALIDATION_NOT_STUN;
  }

  msg->buffer = (uint8_t *) buffer;
  msg->buffer_len = buffer_len;
  msg->agent = agent;
  msg->key = NULL;
  msg->key_len = 0;
  msg->long_term_valid = FALSE;

  /* TODO: reject it or not ? */
  if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
          agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
      !stun_message_has_cookie (msg)) {
      stun_debug ("STUN demux error: no cookie!\n");
      return STUN_VALIDATION_BAD_REQUEST;
  }

  if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
          agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
      agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
    /* Looks for FINGERPRINT */
    if (stun_message_find32 (msg, STUN_ATTRIBUTE_FINGERPRINT, &fpr) !=
        STUN_MESSAGE_RETURN_SUCCESS) {
      stun_debug ("STUN demux error: no FINGERPRINT attribute!\n");
      return STUN_VALIDATION_BAD_REQUEST;
    }
    /* Checks FINGERPRINT */
    crc32 = stun_fingerprint (msg->buffer, stun_message_length (msg),
        agent->compatibility == STUN_COMPATIBILITY_WLM2009);
    fpr = ntohl (fpr);
    if (fpr != crc32) {
      stun_debug ("STUN demux error: bad fingerprint: 0x%08x,"
          " expected: 0x%08x!\n", fpr, crc32);
      return STUN_VALIDATION_BAD_REQUEST;
    }

    stun_debug ("STUN demux: OK!\n");
  }

  if (stun_message_get_class (msg) == STUN_RESPONSE ||
      stun_message_get_class (msg) == STUN_ERROR) {
    stun_message_id (msg, msg_id);
    for (sent_id_idx = 0; sent_id_idx < STUN_AGENT_MAX_SAVED_IDS; sent_id_idx++) {
      if (agent->sent_ids[sent_id_idx].valid == TRUE &&
          agent->sent_ids[sent_id_idx].method == stun_message_get_method (msg) &&
          memcmp (msg_id, agent->sent_ids[sent_id_idx].id,
              sizeof(StunTransactionId)) == 0) {

        key = agent->sent_ids[sent_id_idx].key;
        key_len = agent->sent_ids[sent_id_idx].key_len;
        memcpy (long_term_key, agent->sent_ids[sent_id_idx].long_term_key,
            sizeof(long_term_key));
        long_term_key_valid = agent->sent_ids[sent_id_idx].long_term_valid;
        break;
      }
    }
    if (sent_id_idx == STUN_AGENT_MAX_SAVED_IDS) {
      return STUN_VALIDATION_UNMATCHED_RESPONSE;
    }
  }

  ignore_credentials =
      (agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) ||
      (stun_message_get_class (msg) == STUN_ERROR &&
       stun_message_find_error (msg, &error_code) ==
          STUN_MESSAGE_RETURN_SUCCESS &&
       (error_code == 400 || error_code == 401)) ||
      (stun_message_get_class (msg) == STUN_INDICATION &&
       (agent->usage_flags & STUN_AGENT_USAGE_NO_INDICATION_AUTH));

  if (key == NULL &&
      ignore_credentials == 0 &&
      (stun_message_get_class (msg) == STUN_REQUEST ||
       stun_message_get_class (msg) == STUN_INDICATION) &&
      (((agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS) &&
       (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) ||
        !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY))) ||
      ((agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) &&
        stun_message_get_class (msg) == STUN_REQUEST &&
        (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) ||
         !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) ||
         !stun_message_has_attribute (msg, STUN_ATTRIBUTE_NONCE) ||
         !stun_message_has_attribute (msg, STUN_ATTRIBUTE_REALM))) ||
       ((agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) == 0 &&
         stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) &&
         !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY)))) {
        return STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST;
  }

  if (stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) &&
      ((key == NULL && ignore_credentials == 0) ||
          (agent->usage_flags & STUN_AGENT_USAGE_FORCE_VALIDATER))) {
    username_len = 0;
    username = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_USERNAME,
        &username_len);
    if (validater == NULL ||
        validater (agent, msg, username, username_len,
            &key, &key_len, validater_data) == FALSE) {
      return STUN_VALIDATION_UNAUTHORIZED;
    }
  }

  if (ignore_credentials == 0 && key != NULL && key_len > 0) {
    hash = (uint8_t *) stun_message_find (msg,
        STUN_ATTRIBUTE_MESSAGE_INTEGRITY, &hlen);

    if (hash) {
      /* We must give the size from start to the end of the attribute
         because you might have a FINGERPRINT attribute after it... */
      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;
        uint8_t md5[16];

        if (long_term_key_valid) {
          memcpy (md5, long_term_key, sizeof (md5));
        } else {
          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) {
            return STUN_VALIDATION_UNAUTHORIZED;
          }
          stun_hash_creds (realm, realm_len,
              username,  username_len,
              key, key_len, md5);
        }

        memcpy (msg->long_term_key, md5, sizeof(md5));
        msg->long_term_valid = TRUE;

        if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
          stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer,
              sha, md5, sizeof(md5), TRUE);
        } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
          stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
              stun_message_length (msg) - 20, sha, md5, sizeof(md5), TRUE);
        } else {
          stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
              hash - msg->buffer, sha, md5, sizeof(md5), FALSE);
        }
      } else {
        if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
          stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer,
              sha, key, key_len, TRUE);
        } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
          stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
              stun_message_length (msg) - 20, sha, key, key_len, TRUE);
        } else {
          stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
              hash - msg->buffer, sha, key, key_len, FALSE);
        }
      }

      stun_debug (" Message HMAC-SHA1 fingerprint:");
      stun_debug ("\nkey     : ");
      stun_debug_bytes (key, key_len);
      stun_debug ("\n  expected: ");
      stun_debug_bytes (sha, sizeof (sha));
      stun_debug ("\n  received: ");
      stun_debug_bytes (hash, sizeof (sha));
      stun_debug ("\n");

      if (memcmp (sha, hash, sizeof (sha)))  {
        stun_debug ("STUN auth error: SHA1 fingerprint mismatch!\n");
        return STUN_VALIDATION_UNAUTHORIZED;
      }

      stun_debug ("STUN auth: OK!\n");
      msg->key = key;
      msg->key_len = key_len;
    } else if (!(stun_message_get_class (msg) == STUN_ERROR &&
        stun_message_find_error (msg, &error_code) ==
            STUN_MESSAGE_RETURN_SUCCESS &&
        (error_code == 400 || error_code == 401))) {
      stun_debug ("STUN auth error: No message integrity attribute!\n");
      return STUN_VALIDATION_UNAUTHORIZED;
    }
  }


  if (sent_id_idx != -1 && sent_id_idx < STUN_AGENT_MAX_SAVED_IDS) {
    agent->sent_ids[sent_id_idx].valid = FALSE;
  }

  if (stun_agent_find_unknowns (agent, msg, &unknown, 1) > 0) {
    if (stun_message_get_class (msg) == STUN_REQUEST)
      return STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE;
    else
      return STUN_VALIDATION_UNKNOWN_ATTRIBUTE;
  }
  return STUN_VALIDATION_SUCCESS;

}
Exemplo n.º 3
0
/* Tests for generic message validation routines */
static void test_message (void)
{
  static const uint8_t extra_garbage[] =
      {0x15, 0x55, 0x00, 0x00,
       0x21, 0x12, 0xA4, 0x42, // cookie
       0x76, 0x54, 0x32, 0x10,
       0xfe, 0xdc, 0xba, 0x98,
       0x76, 0x54, 0x32, 0x10,
       0xaa, 0xbb, 0xcc, 0xdd}; //extra garbage
  static const uint8_t simple_resp[] =
      {0x15, 0x55, 0x00, 0x00,
       0x21, 0x12, 0xA4, 0x42, // cookie
       0x76, 0x54, 0x32, 0x10,
       0xfe, 0xdc, 0xba, 0x98,
       0x76, 0x54, 0x32, 0x10};
  static const uint8_t old_ind[] =
      {0x14, 0x55, 0x00, 0x00,
       0xfe, 0xdc, 0xba, 0x98, // NO cookie
       0x76, 0x54, 0x32, 0x10,
       0xfe, 0xdc, 0xba, 0x98,
       0x76, 0x54, 0x32, 0x10};
  static const uint8_t fpr_resp[] =
      {0x15, 0x55, 0x00, 0x10,
       0x21, 0x12, 0xA4, 0x42, // cookie
       0x76, 0x54, 0x32, 0x10,
       0xfe, 0xdc, 0xba, 0x98,
       0x76, 0x54, 0x32, 0x10,
       0x00, 0x06, 0x00, 0x04, // dummy USERNAME header
       0x41, 0x42, 0x43, 0x44,
       0x80, 0x28, 0x00, 0x04, // FINGERPRINT header
       0xdc, 0x8d, 0xa7, 0x74}; // CRC32;
  static const uint8_t bad1[32] =
      {0x15, 0x55, 0x00, 0x08,
       0x21, 0x12, 0xA4, 0x42, // cookie
       0x76, 0x54, 0x32, 0x10,
       0xfe, 0xdc, 0xba, 0x98,
       0x76, 0x54, 0x32, 0x10,
       0x00, 0x06, 0x00, 0x05, // too big attribute for message
       0x11, 0x22, 0x33, 0x44,
       0x55, 0x66, 0x77, 0x88};
  static const uint8_t bad2[24] =
      {0x15, 0x55, 0x00, 0x05, // invalid message length
       0x21, 0x12, 0xA4, 0x42,
       0x76, 0x54, 0x32, 0x10,
       0xfe, 0xdc, 0xba, 0x98,
       0x76, 0x54, 0x32, 0x10,
       0x00, 0x06, 0x00, 0x01};
  static const uint8_t bad3[27] =
      {0x15, 0x55, 0x00, 0x08,
       0x21, 0x12, 0xA4, 0x42,
       0x76, 0x54, 0x32, 0x10,
       0xfe, 0xdc, 0xba, 0x98,
       0x76, 0x54, 0x32, 0x10,
       0x00, 0x06, 0x00, 0x03,
       0x11, 0x22, 0x33}; // missing padding
  static const uint8_t bad_crc[] =
      {0x15, 0x55, 0x00, 0x08,
       0x21, 0x12, 0xA4, 0x42,
       0x76, 0x54, 0x32, 0x10,
       0xfe, 0xdc, 0xba, 0x98,
       0x76, 0x54, 0x32, 0x10,
       0x80, 0x28, 0x00, 0x04, // FINGERPRINT header
       0x04, 0x91, 0xcd, 0x78}; // CRC32
  static uint8_t bad_crc_offset[] =
      {0x15, 0x55, 0x00, 0x10,
       0x21, 0x12, 0xA4, 0x42,
       0x76, 0x54, 0x32, 0x10,
       0xfe, 0xdc, 0xba, 0x98,
       0x20, 0x67, 0xc4, 0x09,
       0x80, 0x28, 0x00, 0x04, // FINGERPRINT header
       0x00, 0x00, 0x00, 0x00,
       0x00, 0x06, 0x00, 0x04,
       0x41, 0x42, 0x43, 0x44};

  static unsigned char req[] =
      {0x00, 0x01, 0x00, 0x00,
       0x8b, 0x45, 0x9b, 0xc3,
       0xe7, 0x7a, 0x05, 0xb3,
       0xe4, 0xfe, 0x01, 0xf0,
       0xaf, 0x83, 0xe1, 0x9e};

  static uint8_t binding_error_resp[] =
      {0x01, 0x11, 0x00, 0x84,
       0x8b, 0x45, 0x9b, 0xc3,
       0xe7, 0x7a, 0x05, 0xb3,
       0xe4, 0xfe, 0x01, 0xf0,
       0xaf, 0x83, 0xe1, 0x9e,

       0x00, 0x06, 0x00, 0x48, // USERNAME
       0x92, 0x6b, 0x2b, 0x3e,
       0x6a, 0xa5, 0x43, 0x58,
       0xa8, 0x51, 0x25, 0xa6,
       0xf7, 0x9c, 0x0a, 0xe7,
       0xd8, 0x86, 0xf7, 0x76,
       0xf9, 0xcd, 0x8a, 0x2e,
       0x45, 0xd7, 0xcb, 0xbb,
       0xae, 0xe5, 0x03, 0xc3,
       0x3a, 0x32, 0x3a, 0xa9,
       0x9e, 0xb7, 0x7b, 0x32,
       0xe3, 0xf3, 0xa6, 0xc0,
       0xe8, 0x54, 0x4b, 0xef,
       0x52, 0xd2, 0xe2, 0xc0,
       0x43, 0xc2, 0x4c, 0xbc,
       0xaf, 0xd9, 0xf2, 0xfa,
       0x48, 0x8b, 0x8c, 0xe6,
       0x62, 0x14, 0x64, 0x3a,
       0x32, 0x00, 0x00, 0x00,

       0x00, 0x09, 0x00, 0x1c, // ERROR-CODE
       0x00, 0x00, 0x04, 0x1f,
       0x49, 0x6e, 0x74, 0x65,
       0x67, 0x72, 0x69, 0x74,
       0x79, 0x20, 0x43, 0x68,
       0x65, 0x63, 0x6b, 0x20,
       0x46, 0x61, 0x69, 0x6c,
       0x75, 0x72, 0x65, 0x2e,

       0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY
       0xf7, 0x46, 0x81, 0xc4,
       0x6f, 0x4c, 0x21, 0x5c,
       0xf6, 0x8e, 0xc0, 0x81,
       0x0e, 0x20, 0x3f, 0xb1,
       0xb1, 0xad, 0xa4, 0x8a};

  StunAgent agent;
  StunAgent agent2;
  StunMessage msg;
  uint16_t known_attributes[] = {STUN_ATTRIBUTE_USERNAME,
                                 STUN_ATTRIBUTE_ERROR_CODE,
                                 STUN_ATTRIBUTE_MESSAGE_INTEGRITY};

  uint8_t username_v[] = {0x92, 0x6b, 0x2b, 0x3e, 0x6a, 0xa5, 0x43, 0x58,
                          0xa8, 0x51, 0x25, 0xa6, 0xf7, 0x9c, 0x0a, 0xe7,
                          0xd8, 0x86, 0xf7, 0x76, 0xf9, 0xcd, 0x8a, 0x2e,
                          0x45, 0xd7, 0xcb, 0xbb, 0xae, 0xe5, 0x03, 0xc3,
                          0x3a, 0x32, 0x3a, 0xa9, 0x9e, 0xb7, 0x7b, 0x32,
                          0xe3, 0xf3, 0xa6, 0xc0, 0xe8, 0x54, 0x4b, 0xef,
                          0x52, 0xd2, 0xe2, 0xc0, 0x43, 0xc2, 0x4c, 0xbc,
                          0xaf, 0xd9, 0xf2, 0xfa, 0x48, 0x8b, 0x8c, 0xe6,
                          0x62, 0x14, 0x64, 0x3a, 0x32, 0x00, 0x00, 0x00};
  uint8_t password_v[]  = {0x77, 0xd9, 0x7a, 0xe9, 0xcf, 0xe0, 0x3e, 0xa2,
                           0x28, 0xa0, 0x5d, 0xec, 0xcf, 0x36, 0xe8, 0x49};

  StunDefaultValidaterData v = {username_v, 72, password_v, 16};

  stun_agent_init (&agent, known_attributes,
      STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT);
  stun_agent_init (&agent2, known_attributes,
      STUN_COMPATIBILITY_RFC3489, STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS);


  stun_agent_validate (&agent2, &msg, req, sizeof(req),  NULL, NULL);
  stun_agent_finish_message (&agent2, &msg, NULL, 0);

  if (stun_agent_validate (&agent2, &msg, binding_error_resp,
          sizeof(binding_error_resp),
          stun_agent_default_validater, &v) != STUN_VALIDATION_SUCCESS)
    fatal ("Binding Error Response failed");


  if (stun_message_validate_buffer_length (NULL, 0, TRUE) !=
      STUN_MESSAGE_BUFFER_INVALID)
    fatal ("0 bytes test failed");
  if (stun_message_validate_buffer_length ((uint8_t *)"\xf0", 1, TRUE) >= 0)
    fatal ("1 byte test failed");
  if (stun_message_validate_buffer_length (bad1, sizeof (bad1), TRUE) >= 0)
    fatal ("Badness 1 test failed");
  if (stun_message_validate_buffer_length (bad2, sizeof (bad2), TRUE) >= 0)
    fatal ("Badness 2 test failed");
  if (stun_message_validate_buffer_length (bad3, sizeof (bad3), TRUE) != 0)
    fatal ("Badness 3 test failed");
  validate (simple_resp, 20);
  validate (old_ind, 20);
  validate (fpr_resp, 36);

  if (stun_agent_validate (&agent, &msg, extra_garbage, sizeof(extra_garbage),
          NULL, NULL) != STUN_VALIDATION_NOT_STUN)
    fatal ("Extra garbage test failed");
  if (stun_agent_validate (&agent, &msg, simple_resp, sizeof(simple_resp),
          NULL, NULL) != STUN_VALIDATION_BAD_REQUEST)
    fatal ("Missing CRC test failed");
  if (stun_agent_validate (&agent, &msg, old_ind, sizeof(old_ind),
          NULL, NULL) != STUN_VALIDATION_BAD_REQUEST)
    fatal ("Missing cookie test failed");
  if (stun_agent_validate (&agent, &msg, bad_crc, sizeof(bad_crc),
          NULL, NULL) != STUN_VALIDATION_BAD_REQUEST)
    fatal ("Bad CRC test failed");
  if (stun_agent_validate (&agent, &msg, bad_crc_offset, sizeof(bad_crc_offset),
          NULL, NULL) != STUN_VALIDATION_BAD_REQUEST)
    fatal ("Bad CRC offset test failed");
  if (stun_agent_validate (&agent, &msg, fpr_resp, sizeof(fpr_resp),
          NULL, NULL) != STUN_VALIDATION_UNMATCHED_RESPONSE)
    fatal ("Good CRC test failed");

  if (stun_message_get_class (&msg) != 3)
    fatal ("Class test failed");
  if (stun_message_get_method (&msg) != 0x525)
    fatal ("Method test failed");
}