Commit b87ba2c9 authored by Steve Holme's avatar Steve Holme
Browse files

email: Added support for cancelling DIGEST-MD5 authentication

parent e7a2ba41
Loading
Loading
Loading
Loading
+67 −42
Original line number Diff line number Diff line
@@ -55,7 +55,7 @@
/* Retrieves the value for a corresponding key from the challenge string
 * returns TRUE if the key could be found, FALSE if it does not exists
 */
static bool sasl_digest_get_key_value(const unsigned char *chlg,
static bool sasl_digest_get_key_value(const char *chlg,
                                      const char *key,
                                      char *value,
                                      size_t max_val_len,
@@ -64,7 +64,7 @@ static bool sasl_digest_get_key_value(const unsigned char *chlg,
  char *find_pos;
  size_t i;

  find_pos = strstr((const char *) chlg, key);
  find_pos = strstr(chlg, key);
  if(!find_pos)
    return FALSE;

@@ -263,6 +263,66 @@ CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data,
  return result;
}

/*
 * Curl_sasl_decode_digest_md5_message()
 *
 * This is used to decode an already encoded DIGEST-MD5 challenge message.
 *
 * Parameters:
 *
 * chlg64  [in]     - Pointer to the base64 encoded challenge buffer.
 * nonce   [in/out] - The buffer where the nonce will be stored.
 * nlen    [in]     - The length of the nonce buffer.
 * realm   [in/out] - The buffer where the realm will be stored.
 * rlen    [in]     - The length of the realm buffer.
 * alg     [in/out] - The buffer where the algorithm will be stored.
 * alen    [in]     - The length of the algorithm buffer.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_sasl_decode_digest_md5_message(const char *chlg64,
                                             char *nonce, size_t nlen,
                                             char *realm, size_t rlen,
                                             char *alg, size_t alen)
{
  CURLcode result = CURLE_OK;
  char *chlg = NULL;
  size_t chlglen = 0;
  size_t chlg64len = strlen(chlg64);

  if(chlg64len && *chlg64 != '=') {
    result = Curl_base64_decode(chlg64, (unsigned char **) &chlg, &chlglen);
    if(result)
      return result;
  }

  /* Ensure we have a valid challenge message */
  if(!chlg)
    return CURLE_BAD_CONTENT_ENCODING;

  /* Retrieve nonce string from the challenge */
  if(!sasl_digest_get_key_value(chlg, "nonce=\"", nonce, nlen, '\"')) {
    Curl_safefree(chlg);
    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Retrieve realm string from the challenge */
  if(!sasl_digest_get_key_value(chlg, "realm=\"", realm, rlen, '\"')) {
    /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
    strcpy(realm, "");
  }

  /* Retrieve algorithm string from the challenge */
  if(!sasl_digest_get_key_value(chlg, "algorithm=", alg, alen, ',')) {
    Curl_safefree(chlg);
    return CURLE_BAD_CONTENT_ENCODING;
  }

  Curl_safefree(chlg);

  return CURLE_OK;
}

/*
 * Curl_sasl_create_digest_md5_message()
 *
@@ -272,10 +332,11 @@ CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data,
 * Parameters:
 *
 * data    [in]     - The session handle.
 * chlg64  [in]     - Pointer to the base64 encoded challenge buffer.
 * nonce   [in]     - The nonce.
 * realm   [in]     - The realm.
 * userp   [in]     - The user name.
 * passdwp [in]     - The user's password.
 * service [in]     - The service type such as www, smtp or pop
 * service [in]     - The service type such as www, smtp, pop or imap.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.
@@ -283,7 +344,8 @@ CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data,
 * Returns CURLE_OK on success.
 */
CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
                                             const char *chlg64,
                                             const char *nonce,
                                             const char *realm,
                                             const char *userp,
                                             const char *passwdp,
                                             const char *service,
@@ -302,9 +364,6 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
  char HA2_hex[2 * MD5_DIGEST_LEN + 1];
  char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];

  char nonce[64];
  char realm[128];
  char alg[64];
  char nonceCount[] = "00000001";
  char cnonce[]     = "12345678"; /* will be changed */
  char method[]     = "AUTHENTICATE";
@@ -312,40 +371,6 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
  char uri[128];
  char response[512];

  result = Curl_base64_decode(chlg64, &chlg, &chlglen);

  if(result)
    return result;

  if(!chlg)
    return CURLE_LOGIN_DENIED;

  /* Retrieve nonce string from the challenge */
  if(!sasl_digest_get_key_value(chlg, "nonce=\"", nonce,
                                sizeof(nonce), '\"')) {
    Curl_safefree(chlg);
    return CURLE_LOGIN_DENIED;
  }

  /* Retrieve realm string from the challenge */
  if(!sasl_digest_get_key_value(chlg, "realm=\"", realm,
                                sizeof(realm), '\"')) {
    /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
    strcpy(realm, "");
  }

  /* Retrieve algorithm string from the challenge */
  if(!sasl_digest_get_key_value(chlg, "algorithm=", alg, sizeof(alg), ',')) {
    Curl_safefree(chlg);
    return CURLE_LOGIN_DENIED;
  }

  Curl_safefree(chlg);

  /* We do not support other algorithms */
  if(strcmp(alg, "md5-sess") != 0)
    return CURLE_LOGIN_DENIED;

#ifndef DEBUGBUILD
  /* Generate 64 bits of random data */
  for(i = 0; i < 8; i++)
+8 −1
Original line number Diff line number Diff line
@@ -77,9 +77,16 @@ CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data,
                                           const char *passwdp,
                                           char **outptr, size_t *outlen);

/* This is used to decode a base64 encoded DIGEST-MD5 challange message */
CURLcode Curl_sasl_decode_digest_md5_message(const char *chlg64,
                                             char *nonce, size_t nlen,
                                             char *realm, size_t rlen,
                                             char *alg, size_t alen);

/* This is used to generate a base64 encoded DIGEST-MD5 response message */
CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
                                             const char *chlg64,
                                             const char *nonce,
                                             const char *realm,
                                             const char *user,
                                             const char *passwdp,
                                             const char *service,
+23 −9
Original line number Diff line number Diff line
@@ -1160,6 +1160,10 @@ static CURLcode imap_state_auth_digest_resp(struct connectdata *conn,
  char *rplyb64 = NULL;
  size_t len = 0;

  char nonce[64];
  char realm[128];
  char algorithm[64];

  (void)instate; /* no use for this yet */

  if(imapcode != '+') {
@@ -1170,22 +1174,32 @@ static CURLcode imap_state_auth_digest_resp(struct connectdata *conn,
  /* Get the challenge message */
  imap_get_message(data->state.buffer, &chlg64);

  /* Create the response message */
  result = Curl_sasl_create_digest_md5_message(data, chlg64, conn->user,
                                               conn->passwd, "imap",
                                               &rplyb64, &len);
  /* Decode the challange message */
  result = Curl_sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
                                               realm, sizeof(realm),
                                               algorithm, sizeof(algorithm));
  if(result || strcmp(algorithm, "md5-sess") != 0) {
    /* Send the cancellation */
    result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*");

    if(!result)
      state(conn, IMAP_AUTHENTICATE_CANCEL);
  }
  else {
    /* Create the response message */
    result = Curl_sasl_create_digest_md5_message(data, nonce, realm,
                                                 conn->user, conn->passwd,
                                                 "imap", &rplyb64, &len);
    if(!result && rplyb64) {
      /* Send the response */
  if(!result) {
    if(rplyb64) {
      result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", rplyb64);

      if(!result)
        state(conn, IMAP_AUTHENTICATE_DIGESTMD5_RESP);
    }
  }

  Curl_safefree(rplyb64);
  }

  return result;
}
+23 −9
Original line number Diff line number Diff line
@@ -1018,6 +1018,10 @@ static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn,
  char *rplyb64 = NULL;
  size_t len = 0;

  char nonce[64];
  char realm[128];
  char algorithm[64];

  (void)instate; /* no use for this yet */

  if(pop3code != '+') {
@@ -1028,22 +1032,32 @@ static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn,
  /* Get the challenge message */
  pop3_get_message(data->state.buffer, &chlg64);

  /* Create the response message */
  result = Curl_sasl_create_digest_md5_message(data, chlg64, conn->user,
                                               conn->passwd, "pop",
                                               &rplyb64, &len);
  /* Decode the challange message */
  result = Curl_sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
                                               realm, sizeof(realm),
                                               algorithm, sizeof(algorithm));
  if(result || strcmp(algorithm, "md5-sess") != 0) {
    /* Send the cancellation */
    result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");

    if(!result)
      state(conn, POP3_AUTH_CANCEL);
  }
  else {
    /* Create the response message */
    result = Curl_sasl_create_digest_md5_message(data, nonce, realm,
                                                 conn->user, conn->passwd,
                                                 "pop", &rplyb64, &len);
    if(!result && rplyb64) {
      /* Send the response */
  if(!result) {
    if(rplyb64) {
      result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);

      if(!result)
        state(conn, POP3_AUTH_DIGESTMD5_RESP);
    }
  }

  Curl_safefree(rplyb64);
  }

  return result;
}
+23 −9
Original line number Diff line number Diff line
@@ -998,6 +998,10 @@ static CURLcode smtp_state_auth_digest_resp(struct connectdata *conn,
  char *rplyb64 = NULL;
  size_t len = 0;

  char nonce[64];
  char realm[128];
  char algorithm[64];

  (void)instate; /* no use for this yet */

  if(smtpcode != 334) {
@@ -1008,22 +1012,32 @@ static CURLcode smtp_state_auth_digest_resp(struct connectdata *conn,
  /* Get the challenge message */
  smtp_get_message(data->state.buffer, &chlg64);

  /* Create the response message */
  result = Curl_sasl_create_digest_md5_message(data, chlg64, conn->user,
                                               conn->passwd, "smtp",
                                               &rplyb64, &len);
  /* Decode the challange message */
  result = Curl_sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
                                               realm, sizeof(realm),
                                               algorithm, sizeof(algorithm));
  if(result || strcmp(algorithm, "md5-sess") != 0) {
    /* Send the cancellation */
    result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*");

    if(!result)
      state(conn, SMTP_AUTH_CANCEL);
  }
  else {
    /* Create the response message */
    result = Curl_sasl_create_digest_md5_message(data, nonce, realm,
                                                 conn->user, conn->passwd,
                                                 "smtp", &rplyb64, &len);
    if(!result && rplyb64) {
      /* Send the response */
  if(!result) {
    if(rplyb64) {
      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);

      if(!result)
        state(conn, SMTP_AUTH_DIGESTMD5_RESP);
    }
  }

  Curl_safefree(rplyb64);
  }

  return result;
}