1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
38
39
40
41
42
43
44
45
46
47
51
52
53
54
55
56
59
60
61
62
63
64
65
73
74
75
76
77
78
79
80
81
82
86
87
88
89
90
93
96
99
100
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
128
129
130
131
132
136
137
138
139
140
141
142
143
144
145
146
149
150
151
152
153
158
161
162
163
168
169
184
185
186
191
192
193
194
199
200
204
205
206
207
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
235
236
237
238
239
240
241
242
243
244
/* ... */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include "sys/socket.h"
#include "esp_rom_md5.h"
#include "esp_tls_crypto.h"
#include "mbedtls/sha256.h"
#include "esp_log.h"
#include "esp_check.h"
#include "http_utils.h"
#include "http_auth.h"12 includes
#define MD5_MAX_LEN (33)
#define SHA256_LEN (32)
#define SHA256_HEX_LEN (65)
#define HTTP_AUTH_BUF_LEN (1024)
static const char *TAG = "HTTP_AUTH";
/* ... */
static int md5_printf(char *md, const char *fmt, ...)
{
unsigned char *buf;
unsigned char digest[MD5_MAX_LEN];
int len, i;
md5_context_t md5_ctx;
va_list ap;
va_start(ap, fmt);
len = vasprintf((char **)&buf, fmt, ap);
if (buf == NULL) {
va_end(ap);
return ESP_FAIL;
}{...}
esp_rom_md5_init(&md5_ctx);
esp_rom_md5_update(&md5_ctx, buf, len);
esp_rom_md5_final(digest, &md5_ctx);
for (i = 0; i < 16; ++i) {
sprintf(&md[i * 2], "%02x", (unsigned int)digest[i]);
}{...}
va_end(ap);
free(buf);
return MD5_MAX_LEN;
}{ ... }
/* ... */
static int sha256_sprintf(char *sha, const char *fmt, ...)
{
unsigned char *buf;
unsigned char digest[SHA256_LEN];
int len, i;
va_list ap;
va_start(ap, fmt);
len = vasprintf((char **)&buf, fmt, ap);
if (buf == NULL) {
va_end(ap);
return ESP_FAIL;
}{...}
int ret = 0;
mbedtls_sha256_context sha256;
mbedtls_sha256_init(&sha256);
if (mbedtls_sha256_starts(&sha256, 0) != 0) {
goto exit;
}{...}
if (mbedtls_sha256_update(&sha256, buf, len) != 0) {
goto exit;
}{...}
if (mbedtls_sha256_finish(&sha256, digest) != 0) {
goto exit;
}{...}
for (i = 0; i < 32; ++i) {
sprintf(&sha[i * 2], "%02x", (unsigned int)digest[i]);
}{...}
sha[SHA256_HEX_LEN - 1] = '\0';
ret = SHA256_HEX_LEN;
exit:
free(buf);
mbedtls_sha256_free(&sha256);
va_end(ap);
return ret;
}{ ... }
char *http_auth_digest(const char *username, const char *password, esp_http_auth_data_t *auth_data)
{
char *ha1, *ha2 = NULL;
char *digest = NULL;
char *auth_str = NULL;
char *temp_auth_str = NULL;
esp_err_t ret = ESP_OK;
if (username == NULL ||
password == NULL ||
auth_data->nonce == NULL ||
auth_data->uri == NULL ||
auth_data->realm == NULL) {
return NULL;
}{...}
int digest_size = MD5_MAX_LEN;
int (*digest_func)(char *digest, const char *fmt, ...) = md5_printf;
if (!memcmp(auth_data->algorithm, "SHA256", strlen("SHA256")) ||
!memcmp(auth_data->algorithm, "SHA-256", strlen("SHA-256"))) {
digest_size = SHA256_HEX_LEN;
digest_func = sha256_sprintf;
}{...}
ha1 = calloc(1, digest_size);
ESP_GOTO_ON_FALSE(ha1, ESP_FAIL, _digest_exit, TAG, "Memory exhausted");
ha2 = calloc(1, digest_size);
ESP_GOTO_ON_FALSE(ha2, ESP_FAIL, _digest_exit, TAG, "Memory exhausted");
digest = calloc(1, digest_size);
ESP_GOTO_ON_FALSE(digest, ESP_FAIL, _digest_exit, TAG, "Memory exhausted");
if (digest_func(ha1, "%s:%s:%s", username, auth_data->realm, password) <= 0) {
goto _digest_exit;
}{...}
ESP_LOGD(TAG, "%s %s %s %s", "Digest", username, auth_data->realm, password);
if ((strcasecmp(auth_data->algorithm, "md5-sess") == 0) ||
(strcasecmp(auth_data->algorithm, "SHA256") == 0) ||
(strcasecmp(auth_data->algorithm, "md5-sess") == 0)) {
if (digest_func(ha1, "%s:%s:%016llx", ha1, auth_data->nonce, auth_data->cnonce) <= 0) {
goto _digest_exit;
}{...}
}{...}
if (digest_func(ha2, "%s:%s", auth_data->method, auth_data->uri) <= 0) {
goto _digest_exit;
}{...}
if (auth_data->qop && strcasecmp(auth_data->qop, "auth-int") == 0) {
if (digest_func(ha2, "%s:%s", ha2, "entity") <= 0) {
goto _digest_exit;
}{...}
}{...}
if (auth_data->qop) {
if (digest_func(digest, "%s:%s:%08x:%016llx:%s:%s", ha1, auth_data->nonce, auth_data->nc, auth_data->cnonce, auth_data->qop, ha2) <= 0) {
goto _digest_exit;
}{...}
}{...} else {
/* ... */
ESP_LOGW(TAG, "\"qop\" directive not found. This may lead to attacks like chosen-plaintext attack");
if (digest_func(digest, "%s:%s:%s", ha1, auth_data->nonce, ha2) <= 0) {
goto _digest_exit;
}{...}
}{...}
int rc = asprintf(&auth_str, "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", algorithm=%s, "
"response=\"%s\"", username, auth_data->realm, auth_data->nonce, auth_data->uri, auth_data->algorithm, digest);
if (rc < 0) {
ESP_LOGE(TAG, "asprintf() returned: %d", rc);
ret = ESP_FAIL;
goto _digest_exit;
}{...}
if (auth_data->qop) {
rc = asprintf(&temp_auth_str, ", qop=%s, nc=%08x, cnonce=\"%016"PRIx64"\"", auth_data->qop, auth_data->nc, auth_data->cnonce);
if (rc < 0) {
ESP_LOGE(TAG, "asprintf() returned: %d", rc);
ret = ESP_FAIL;
goto _digest_exit;
}{...}
auth_str = http_utils_append_string(&auth_str, temp_auth_str, strlen(temp_auth_str));
if (!auth_str) {
ret = ESP_FAIL;
goto _digest_exit;
}{...}
free(temp_auth_str);
auth_data->nc ++;
}{...}
if (auth_data->opaque) {
rc = asprintf(&temp_auth_str, "%s, opaque=\"%s\"", auth_str, auth_data->opaque);
free(auth_str);
if (rc < 0) {
ESP_LOGE(TAG, "asprintf() returned: %d", rc);
ret = ESP_FAIL;
goto _digest_exit;
}{...}
auth_str = temp_auth_str;
}{...}
_digest_exit:
free(ha1);
free(ha2);
free(digest);
return (ret == ESP_OK) ? auth_str : NULL;
}{ ... }
char *http_auth_basic(const char *username, const char *password)
{
size_t out;
char *user_info = NULL;
char *digest = NULL;
esp_err_t ret = ESP_OK;
size_t n = 0;
if (asprintf(&user_info, "%s:%s", username, password) < 0) {
return NULL;
}{...}
ESP_RETURN_ON_FALSE(user_info, NULL, TAG, "Memory exhausted");
esp_crypto_base64_encode(NULL, 0, &n, (const unsigned char *)user_info, strlen(user_info));
digest = calloc(1, 6 + n + 1);
ESP_GOTO_ON_FALSE(digest, ESP_FAIL, _basic_exit, TAG, "Memory exhausted");
strcpy(digest, "Basic ");
esp_crypto_base64_encode((unsigned char *)digest + 6, n, &out, (const unsigned char *)user_info, strlen(user_info));
_basic_exit:
free(user_info);
return (ret == ESP_OK) ? digest : NULL;
}{ ... }