mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-26 02:02:02 +00:00
wpa_supplicant: Port dpp feature from supplicant
Add files required for DPP feature from upstream. These file expose the functionality to create DPP packets. Ported crypto layer from openssl to mbedtls. Interfacing to use these API will be added in seperate commit
This commit is contained in:
@@ -1,41 +1,36 @@
|
||||
/*
|
||||
* Base64 encoding/decoding (RFC1341)
|
||||
* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2005-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "includes.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "base64.h"
|
||||
|
||||
static const unsigned char base64_table[65] =
|
||||
static const char base64_table[65] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char base64_url_table[65] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
|
||||
/**
|
||||
* base64_encode - Base64 encode
|
||||
* @src: Data to be encoded
|
||||
* @len: Length of the data to be encoded
|
||||
* @out_len: Pointer to output length variable, or %NULL if not used
|
||||
* Returns: Allocated buffer of out_len bytes of encoded data,
|
||||
* or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer. Returned buffer is
|
||||
* nul terminated to make it easier to use as a C string. The nul terminator is
|
||||
* not included in out_len.
|
||||
*/
|
||||
unsigned char * base64_encode(const unsigned char *src, size_t len,
|
||||
size_t *out_len)
|
||||
|
||||
static char * base64_gen_encode(const unsigned char *src, size_t len,
|
||||
size_t *out_len, const char *table, int add_pad)
|
||||
{
|
||||
unsigned char *out, *pos;
|
||||
char *out, *pos;
|
||||
const unsigned char *end, *in;
|
||||
size_t olen;
|
||||
int line_len;
|
||||
|
||||
if (len >= SIZE_MAX / 4)
|
||||
return NULL;
|
||||
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
|
||||
olen += olen / 72; /* line feeds */
|
||||
if (add_pad)
|
||||
olen += olen / 72; /* line feeds */
|
||||
olen++; /* nul termination */
|
||||
if (olen < len)
|
||||
return NULL; /* integer overflow */
|
||||
@@ -48,33 +43,35 @@ unsigned char * base64_encode(const unsigned char *src, size_t len,
|
||||
pos = out;
|
||||
line_len = 0;
|
||||
while (end - in >= 3) {
|
||||
*pos++ = base64_table[in[0] >> 2];
|
||||
*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
|
||||
*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
|
||||
*pos++ = base64_table[in[2] & 0x3f];
|
||||
*pos++ = table[(in[0] >> 2) & 0x3f];
|
||||
*pos++ = table[(((in[0] & 0x03) << 4) | (in[1] >> 4)) & 0x3f];
|
||||
*pos++ = table[(((in[1] & 0x0f) << 2) | (in[2] >> 6)) & 0x3f];
|
||||
*pos++ = table[in[2] & 0x3f];
|
||||
in += 3;
|
||||
line_len += 4;
|
||||
if (line_len >= 72) {
|
||||
if (add_pad && line_len >= 72) {
|
||||
*pos++ = '\n';
|
||||
line_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (end - in) {
|
||||
*pos++ = base64_table[in[0] >> 2];
|
||||
*pos++ = table[(in[0] >> 2) & 0x3f];
|
||||
if (end - in == 1) {
|
||||
*pos++ = base64_table[(in[0] & 0x03) << 4];
|
||||
*pos++ = '=';
|
||||
*pos++ = table[((in[0] & 0x03) << 4) & 0x3f];
|
||||
if (add_pad)
|
||||
*pos++ = '=';
|
||||
} else {
|
||||
*pos++ = base64_table[((in[0] & 0x03) << 4) |
|
||||
(in[1] >> 4)];
|
||||
*pos++ = base64_table[(in[1] & 0x0f) << 2];
|
||||
*pos++ = table[(((in[0] & 0x03) << 4) |
|
||||
(in[1] >> 4)) & 0x3f];
|
||||
*pos++ = table[((in[1] & 0x0f) << 2) & 0x3f];
|
||||
}
|
||||
*pos++ = '=';
|
||||
if (add_pad)
|
||||
*pos++ = '=';
|
||||
line_len += 4;
|
||||
}
|
||||
|
||||
if (line_len)
|
||||
if (add_pad && line_len)
|
||||
*pos++ = '\n';
|
||||
|
||||
*pos = '\0';
|
||||
@@ -84,49 +81,47 @@ unsigned char * base64_encode(const unsigned char *src, size_t len,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* base64_decode - Base64 decode
|
||||
* @src: Data to be decoded
|
||||
* @len: Length of the data to be decoded
|
||||
* @out_len: Pointer to output length variable
|
||||
* Returns: Allocated buffer of out_len bytes of decoded data,
|
||||
* or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer.
|
||||
*/
|
||||
unsigned char * base64_decode(const unsigned char *src, size_t len,
|
||||
size_t *out_len)
|
||||
static unsigned char * base64_gen_decode(const char *src, size_t len,
|
||||
size_t *out_len, const char *table)
|
||||
{
|
||||
unsigned char dtable[256], *out, *pos, block[4], tmp;
|
||||
size_t i, count, olen;
|
||||
int pad = 0;
|
||||
size_t extra_pad;
|
||||
|
||||
os_memset(dtable, 0x80, 256);
|
||||
for (i = 0; i < sizeof(base64_table) - 1; i++)
|
||||
dtable[base64_table[i]] = (unsigned char) i;
|
||||
dtable[(unsigned char) table[i]] = (unsigned char) i;
|
||||
dtable['='] = 0;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (dtable[src[i]] != 0x80)
|
||||
if (dtable[(unsigned char) src[i]] != 0x80)
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0 || count % 4)
|
||||
if (count == 0)
|
||||
return NULL;
|
||||
extra_pad = (4 - count % 4) % 4;
|
||||
|
||||
olen = count / 4 * 3;
|
||||
olen = (count + extra_pad) / 4 * 3;
|
||||
pos = out = os_malloc(olen);
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
tmp = dtable[src[i]];
|
||||
for (i = 0; i < len + extra_pad; i++) {
|
||||
unsigned char val;
|
||||
|
||||
if (i >= len)
|
||||
val = '=';
|
||||
else
|
||||
val = src[i];
|
||||
tmp = dtable[val];
|
||||
if (tmp == 0x80)
|
||||
continue;
|
||||
|
||||
if (src[i] == '=')
|
||||
if (val == '=')
|
||||
pad++;
|
||||
block[count] = tmp;
|
||||
count++;
|
||||
@@ -153,3 +148,49 @@ unsigned char * base64_decode(const unsigned char *src, size_t len,
|
||||
*out_len = pos - out;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* base64_encode - Base64 encode
|
||||
* @src: Data to be encoded
|
||||
* @len: Length of the data to be encoded
|
||||
* @out_len: Pointer to output length variable, or %NULL if not used
|
||||
* Returns: Allocated buffer of out_len bytes of encoded data,
|
||||
* or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer. Returned buffer is
|
||||
* nul terminated to make it easier to use as a C string. The nul terminator is
|
||||
* not included in out_len.
|
||||
*/
|
||||
char * base64_encode(const void *src, size_t len, size_t *out_len)
|
||||
{
|
||||
return base64_gen_encode(src, len, out_len, base64_table, 1);
|
||||
}
|
||||
|
||||
|
||||
char * base64_url_encode(const void *src, size_t len, size_t *out_len)
|
||||
{
|
||||
return base64_gen_encode(src, len, out_len, base64_url_table, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* base64_decode - Base64 decode
|
||||
* @src: Data to be decoded
|
||||
* @len: Length of the data to be decoded
|
||||
* @out_len: Pointer to output length variable
|
||||
* Returns: Allocated buffer of out_len bytes of decoded data,
|
||||
* or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer.
|
||||
*/
|
||||
unsigned char * base64_decode(const char *src, size_t len, size_t *out_len)
|
||||
{
|
||||
return base64_gen_decode(src, len, out_len, base64_table);
|
||||
}
|
||||
|
||||
|
||||
unsigned char * base64_url_decode(const char *src, size_t len, size_t *out_len)
|
||||
{
|
||||
return base64_gen_decode(src, len, out_len, base64_url_table);
|
||||
}
|
||||
|
@@ -2,22 +2,16 @@
|
||||
* Base64 encoding/decoding (RFC1341)
|
||||
* Copyright (c) 2005, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef BASE64_H
|
||||
#define BASE64_H
|
||||
|
||||
unsigned char * base64_encode(const unsigned char *src, size_t len,
|
||||
size_t *out_len);
|
||||
unsigned char * base64_decode(const unsigned char *src, size_t len,
|
||||
size_t *out_len);
|
||||
char * base64_encode(const void *src, size_t len, size_t *out_len);
|
||||
unsigned char * base64_decode(const char *src, size_t len, size_t *out_len);
|
||||
char * base64_url_encode(const void *src, size_t len, size_t *out_len);
|
||||
unsigned char * base64_url_decode(const char *src, size_t len, size_t *out_len);
|
||||
|
||||
#endif /* BASE64_H */
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include <time.h>
|
||||
|
||||
/**
|
||||
* inc_byte_array - Increment arbitrary length byte array by one
|
||||
@@ -365,4 +366,128 @@ void wpa_bin_clear_free(void *bin, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
int int_array_len(const int *a)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; a && a[i]; i++)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
void bin_clear_free(void *bin, size_t len)
|
||||
{
|
||||
if (bin) {
|
||||
os_memset(bin, 0, len);
|
||||
os_free(bin);
|
||||
}
|
||||
}
|
||||
|
||||
void str_clear_free(char *str)
|
||||
{
|
||||
if (str) {
|
||||
size_t len = os_strlen(str);
|
||||
os_memset(str, 0, len);
|
||||
os_free(str);
|
||||
}
|
||||
}
|
||||
|
||||
int os_gmtime(os_time_t t, struct os_tm *tm)
|
||||
{
|
||||
struct tm *tm2;
|
||||
time_t t2 = t;
|
||||
|
||||
tm2 = gmtime(&t2);
|
||||
if (tm2 == NULL)
|
||||
return -1;
|
||||
tm->sec = tm2->tm_sec;
|
||||
tm->min = tm2->tm_min;
|
||||
tm->hour = tm2->tm_hour;
|
||||
tm->day = tm2->tm_mday;
|
||||
tm->month = tm2->tm_mon + 1;
|
||||
tm->year = tm2->tm_year + 1900;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int os_mktime(int year, int month, int day, int hour, int min, int sec,
|
||||
os_time_t *t)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
|
||||
hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
|
||||
sec > 60)
|
||||
return -1;
|
||||
|
||||
os_memset(&tm, 0, sizeof(tm));
|
||||
tm.tm_year = year - 1900;
|
||||
tm.tm_mon = month - 1;
|
||||
tm.tm_mday = day;
|
||||
tm.tm_hour = hour;
|
||||
tm.tm_min = min;
|
||||
tm.tm_sec = sec;
|
||||
|
||||
*t = (os_time_t) mktime(&tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char * get_param(const char *cmd, const char *param)
|
||||
{
|
||||
const char *pos, *end;
|
||||
char *val;
|
||||
size_t len;
|
||||
|
||||
pos = os_strstr(cmd, param);
|
||||
if (!pos)
|
||||
return NULL;
|
||||
|
||||
pos += os_strlen(param);
|
||||
end = os_strchr(pos, ' ');
|
||||
if (end)
|
||||
len = end - pos;
|
||||
else
|
||||
len = os_strlen(pos);
|
||||
val = os_malloc(len + 1);
|
||||
if (!val)
|
||||
return NULL;
|
||||
os_memcpy(val, pos, len);
|
||||
val[len] = '\0';
|
||||
return val;
|
||||
}
|
||||
|
||||
void * os_memdup(const void *src, size_t len)
|
||||
{
|
||||
void *r = os_malloc(len);
|
||||
|
||||
if (r && src)
|
||||
os_memcpy(r, src, len);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* hwaddr_aton2 - Convert ASCII string to MAC address (in any known format)
|
||||
* @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455)
|
||||
* @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
|
||||
* Returns: Characters used (> 0) on success, -1 on failure
|
||||
*/
|
||||
int hwaddr_aton2(const char *txt, u8 *addr)
|
||||
{
|
||||
int i;
|
||||
const char *pos = txt;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
int a, b;
|
||||
|
||||
while (*pos == ':' || *pos == '.' || *pos == '-')
|
||||
pos++;
|
||||
|
||||
a = hex2num(*pos++);
|
||||
if (a < 0)
|
||||
return -1;
|
||||
b = hex2num(*pos++);
|
||||
if (b < 0)
|
||||
return -1;
|
||||
*addr++ = (a << 4) | b;
|
||||
}
|
||||
|
||||
return pos - txt;
|
||||
}
|
||||
|
@@ -434,6 +434,11 @@ struct wpa_freq_range_list {
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
void wpa_bin_clear_free(void *bin, size_t len);
|
||||
int int_array_len(const int *a);
|
||||
void bin_clear_free(void *bin, size_t len);
|
||||
void str_clear_free(char *str);
|
||||
char * get_param(const char *cmd, const char *param);
|
||||
void * os_memdup(const void *src, size_t len);
|
||||
|
||||
/*
|
||||
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
|
||||
|
654
components/wpa_supplicant/src/utils/json.c
Normal file
654
components/wpa_supplicant/src/utils/json.c
Normal file
@@ -0,0 +1,654 @@
|
||||
/*
|
||||
* JavaScript Object Notation (JSON) parser (RFC7159)
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "base64.h"
|
||||
#include "json.h"
|
||||
|
||||
#define JSON_MAX_DEPTH 10
|
||||
#define JSON_MAX_TOKENS 500
|
||||
|
||||
|
||||
void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len)
|
||||
{
|
||||
char *end = txt + maxlen;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (txt + 4 >= end)
|
||||
break;
|
||||
|
||||
switch (data[i]) {
|
||||
case '\"':
|
||||
*txt++ = '\\';
|
||||
*txt++ = '\"';
|
||||
break;
|
||||
case '\\':
|
||||
*txt++ = '\\';
|
||||
*txt++ = '\\';
|
||||
break;
|
||||
case '\n':
|
||||
*txt++ = '\\';
|
||||
*txt++ = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
*txt++ = '\\';
|
||||
*txt++ = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
*txt++ = '\\';
|
||||
*txt++ = 't';
|
||||
break;
|
||||
default:
|
||||
if (data[i] >= 32 && data[i] <= 126) {
|
||||
*txt++ = data[i];
|
||||
} else {
|
||||
txt += os_snprintf(txt, end - txt, "\\u%04x",
|
||||
(unsigned char) data[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*txt = '\0';
|
||||
}
|
||||
|
||||
|
||||
static char * json_parse_string(const char **json_pos, const char *end)
|
||||
{
|
||||
const char *pos = *json_pos;
|
||||
char *str, *spos, *s_end;
|
||||
size_t max_len, buf_len;
|
||||
u8 bin[2];
|
||||
|
||||
pos++; /* skip starting quote */
|
||||
|
||||
max_len = end - pos + 1;
|
||||
buf_len = max_len > 10 ? 10 : max_len;
|
||||
str = os_malloc(buf_len);
|
||||
if (!str)
|
||||
return NULL;
|
||||
spos = str;
|
||||
s_end = str + buf_len;
|
||||
|
||||
for (; pos < end; pos++) {
|
||||
if (buf_len < max_len && s_end - spos < 3) {
|
||||
char *tmp;
|
||||
int idx;
|
||||
|
||||
idx = spos - str;
|
||||
buf_len *= 2;
|
||||
if (buf_len > max_len)
|
||||
buf_len = max_len;
|
||||
tmp = os_realloc(str, buf_len);
|
||||
if (!tmp)
|
||||
goto fail;
|
||||
str = tmp;
|
||||
spos = str + idx;
|
||||
s_end = str + buf_len;
|
||||
}
|
||||
|
||||
switch (*pos) {
|
||||
case '\"': /* end string */
|
||||
*spos = '\0';
|
||||
/* caller will move to the next position */
|
||||
*json_pos = pos;
|
||||
return str;
|
||||
case '\\':
|
||||
pos++;
|
||||
if (pos >= end) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Truncated \\ escape");
|
||||
goto fail;
|
||||
}
|
||||
switch (*pos) {
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/':
|
||||
*spos++ = *pos;
|
||||
break;
|
||||
case 'n':
|
||||
*spos++ = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
*spos++ = '\r';
|
||||
break;
|
||||
case 't':
|
||||
*spos++ = '\t';
|
||||
break;
|
||||
case 'u':
|
||||
if (end - pos < 5 ||
|
||||
hexstr2bin(pos + 1, bin, 2) < 0 ||
|
||||
bin[1] == 0x00) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid \\u escape");
|
||||
goto fail;
|
||||
}
|
||||
if (bin[0] == 0x00) {
|
||||
*spos++ = bin[1];
|
||||
} else {
|
||||
*spos++ = bin[0];
|
||||
*spos++ = bin[1];
|
||||
}
|
||||
pos += 4;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Unknown escape '%c'", *pos);
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*spos++ = *pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
os_free(str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int json_parse_number(const char **json_pos, const char *end,
|
||||
int *ret_val)
|
||||
{
|
||||
const char *pos = *json_pos;
|
||||
size_t len;
|
||||
char *str;
|
||||
|
||||
for (; pos < end; pos++) {
|
||||
if (*pos != '-' && (*pos < '0' || *pos > '9')) {
|
||||
pos--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pos == end)
|
||||
pos--;
|
||||
if (pos < *json_pos)
|
||||
return -1;
|
||||
len = pos - *json_pos + 1;
|
||||
str = os_malloc(len + 1);
|
||||
if (!str)
|
||||
return -1;
|
||||
os_memcpy(str, *json_pos, len);
|
||||
str[len] = '\0';
|
||||
|
||||
*ret_val = atoi(str);
|
||||
os_free(str);
|
||||
*json_pos = pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int json_check_tree_state(struct json_token *token)
|
||||
{
|
||||
if (!token)
|
||||
return 0;
|
||||
if (json_check_tree_state(token->child) < 0 ||
|
||||
json_check_tree_state(token->sibling) < 0)
|
||||
return -1;
|
||||
if (token->state != JSON_COMPLETED) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Unexpected token state %d (name=%s type=%d)",
|
||||
token->state, token->name ? token->name : "N/A",
|
||||
token->type);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct json_token * json_alloc_token(unsigned int *tokens)
|
||||
{
|
||||
(*tokens)++;
|
||||
if (*tokens > JSON_MAX_TOKENS) {
|
||||
wpa_printf(MSG_DEBUG, "JSON: Maximum token limit exceeded");
|
||||
return NULL;
|
||||
}
|
||||
return os_zalloc(sizeof(struct json_token));
|
||||
}
|
||||
|
||||
|
||||
struct json_token * json_parse(const char *data, size_t data_len)
|
||||
{
|
||||
struct json_token *root = NULL, *curr_token = NULL, *token = NULL;
|
||||
const char *pos, *end;
|
||||
char *str;
|
||||
int num;
|
||||
unsigned int depth = 0;
|
||||
unsigned int tokens = 0;
|
||||
|
||||
pos = data;
|
||||
end = data + data_len;
|
||||
|
||||
for (; pos < end; pos++) {
|
||||
switch (*pos) {
|
||||
case '[': /* start array */
|
||||
case '{': /* start object */
|
||||
if (!curr_token) {
|
||||
token = json_alloc_token(&tokens);
|
||||
if (!token)
|
||||
goto fail;
|
||||
if (!root)
|
||||
root = token;
|
||||
} else if (curr_token->state == JSON_WAITING_VALUE) {
|
||||
token = curr_token;
|
||||
} else if (curr_token->parent &&
|
||||
curr_token->parent->type == JSON_ARRAY &&
|
||||
curr_token->parent->state == JSON_STARTED &&
|
||||
curr_token->state == JSON_EMPTY) {
|
||||
token = curr_token;
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid state for start array/object");
|
||||
goto fail;
|
||||
}
|
||||
depth++;
|
||||
if (depth > JSON_MAX_DEPTH) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Max depth exceeded");
|
||||
goto fail;
|
||||
}
|
||||
token->type = *pos == '[' ? JSON_ARRAY : JSON_OBJECT;
|
||||
token->state = JSON_STARTED;
|
||||
token->child = json_alloc_token(&tokens);
|
||||
if (!token->child)
|
||||
goto fail;
|
||||
curr_token = token->child;
|
||||
curr_token->parent = token;
|
||||
curr_token->state = JSON_EMPTY;
|
||||
break;
|
||||
case ']': /* end array */
|
||||
case '}': /* end object */
|
||||
if (!curr_token || !curr_token->parent ||
|
||||
curr_token->parent->state != JSON_STARTED) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid state for end array/object");
|
||||
goto fail;
|
||||
}
|
||||
depth--;
|
||||
curr_token = curr_token->parent;
|
||||
if ((*pos == ']' &&
|
||||
curr_token->type != JSON_ARRAY) ||
|
||||
(*pos == '}' &&
|
||||
curr_token->type != JSON_OBJECT)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Array/Object mismatch");
|
||||
goto fail;
|
||||
}
|
||||
if (curr_token->child->state == JSON_EMPTY &&
|
||||
!curr_token->child->child &&
|
||||
!curr_token->child->sibling) {
|
||||
/* Remove pending child token since the
|
||||
* array/object was empty. */
|
||||
json_free(curr_token->child);
|
||||
curr_token->child = NULL;
|
||||
}
|
||||
curr_token->state = JSON_COMPLETED;
|
||||
break;
|
||||
case '\"': /* string */
|
||||
str = json_parse_string(&pos, end);
|
||||
if (!str)
|
||||
goto fail;
|
||||
if (!curr_token) {
|
||||
token = json_alloc_token(&tokens);
|
||||
if (!token) {
|
||||
os_free(str);
|
||||
goto fail;
|
||||
}
|
||||
token->type = JSON_STRING;
|
||||
token->string = str;
|
||||
token->state = JSON_COMPLETED;
|
||||
} else if (curr_token->parent &&
|
||||
curr_token->parent->type == JSON_ARRAY &&
|
||||
curr_token->parent->state == JSON_STARTED &&
|
||||
curr_token->state == JSON_EMPTY) {
|
||||
curr_token->string = str;
|
||||
curr_token->state = JSON_COMPLETED;
|
||||
curr_token->type = JSON_STRING;
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"JSON: String value: '%s'",
|
||||
curr_token->string);
|
||||
} else if (curr_token->state == JSON_EMPTY) {
|
||||
curr_token->type = JSON_VALUE;
|
||||
curr_token->name = str;
|
||||
curr_token->state = JSON_STARTED;
|
||||
} else if (curr_token->state == JSON_WAITING_VALUE) {
|
||||
curr_token->string = str;
|
||||
curr_token->state = JSON_COMPLETED;
|
||||
curr_token->type = JSON_STRING;
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"JSON: String value: '%s' = '%s'",
|
||||
curr_token->name,
|
||||
curr_token->string);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid state for a string");
|
||||
os_free(str);
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
/* ignore whitespace */
|
||||
break;
|
||||
case ':': /* name/value separator */
|
||||
if (!curr_token || curr_token->state != JSON_STARTED)
|
||||
goto fail;
|
||||
curr_token->state = JSON_WAITING_VALUE;
|
||||
break;
|
||||
case ',': /* member separator */
|
||||
if (!curr_token)
|
||||
goto fail;
|
||||
curr_token->sibling = json_alloc_token(&tokens);
|
||||
if (!curr_token->sibling)
|
||||
goto fail;
|
||||
curr_token->sibling->parent = curr_token->parent;
|
||||
curr_token = curr_token->sibling;
|
||||
curr_token->state = JSON_EMPTY;
|
||||
break;
|
||||
case 't': /* true */
|
||||
case 'f': /* false */
|
||||
case 'n': /* null */
|
||||
if (!((end - pos >= 4 &&
|
||||
os_strncmp(pos, "true", 4) == 0) ||
|
||||
(end - pos >= 5 &&
|
||||
os_strncmp(pos, "false", 5) == 0) ||
|
||||
(end - pos >= 4 &&
|
||||
os_strncmp(pos, "null", 4) == 0))) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid literal name");
|
||||
goto fail;
|
||||
}
|
||||
if (!curr_token) {
|
||||
token = json_alloc_token(&tokens);
|
||||
if (!token)
|
||||
goto fail;
|
||||
curr_token = token;
|
||||
} else if (curr_token->state == JSON_WAITING_VALUE) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"JSON: Literal name: '%s' = %c",
|
||||
curr_token->name, *pos);
|
||||
} else if (curr_token->parent &&
|
||||
curr_token->parent->type == JSON_ARRAY &&
|
||||
curr_token->parent->state == JSON_STARTED &&
|
||||
curr_token->state == JSON_EMPTY) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"JSON: Literal name: %c", *pos);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid state for a literal name");
|
||||
goto fail;
|
||||
}
|
||||
switch (*pos) {
|
||||
case 't':
|
||||
curr_token->type = JSON_BOOLEAN;
|
||||
curr_token->number = 1;
|
||||
pos += 3;
|
||||
break;
|
||||
case 'f':
|
||||
curr_token->type = JSON_BOOLEAN;
|
||||
curr_token->number = 0;
|
||||
pos += 4;
|
||||
break;
|
||||
case 'n':
|
||||
curr_token->type = JSON_NULL;
|
||||
pos += 3;
|
||||
break;
|
||||
}
|
||||
curr_token->state = JSON_COMPLETED;
|
||||
break;
|
||||
case '-':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
/* number */
|
||||
if (json_parse_number(&pos, end, &num) < 0)
|
||||
goto fail;
|
||||
if (!curr_token) {
|
||||
token = json_alloc_token(&tokens);
|
||||
if (!token)
|
||||
goto fail;
|
||||
token->type = JSON_NUMBER;
|
||||
token->number = num;
|
||||
token->state = JSON_COMPLETED;
|
||||
} else if (curr_token->state == JSON_WAITING_VALUE) {
|
||||
curr_token->number = num;
|
||||
curr_token->state = JSON_COMPLETED;
|
||||
curr_token->type = JSON_NUMBER;
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"JSON: Number value: '%s' = '%d'",
|
||||
curr_token->name,
|
||||
curr_token->number);
|
||||
} else if (curr_token->parent &&
|
||||
curr_token->parent->type == JSON_ARRAY &&
|
||||
curr_token->parent->state == JSON_STARTED &&
|
||||
curr_token->state == JSON_EMPTY) {
|
||||
curr_token->number = num;
|
||||
curr_token->state = JSON_COMPLETED;
|
||||
curr_token->type = JSON_NUMBER;
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"JSON: Number value: %d",
|
||||
curr_token->number);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid state for a number");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Unexpected JSON character: %c", *pos);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!root)
|
||||
root = token;
|
||||
if (!curr_token)
|
||||
curr_token = token;
|
||||
}
|
||||
|
||||
if (json_check_tree_state(root) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "JSON: Incomplete token in the tree");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return root;
|
||||
fail:
|
||||
wpa_printf(MSG_DEBUG, "JSON: Parsing failed");
|
||||
json_free(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void json_free(struct json_token *json)
|
||||
{
|
||||
if (!json)
|
||||
return;
|
||||
json_free(json->child);
|
||||
json_free(json->sibling);
|
||||
os_free(json->name);
|
||||
os_free(json->string);
|
||||
os_free(json);
|
||||
}
|
||||
|
||||
|
||||
struct json_token * json_get_member(struct json_token *json, const char *name)
|
||||
{
|
||||
struct json_token *token, *ret = NULL;
|
||||
|
||||
if (!json || json->type != JSON_OBJECT)
|
||||
return NULL;
|
||||
/* Return last matching entry */
|
||||
for (token = json->child; token; token = token->sibling) {
|
||||
if (token->name && os_strcmp(token->name, name) == 0)
|
||||
ret = token;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * json_get_member_base64url(struct json_token *json,
|
||||
const char *name)
|
||||
{
|
||||
struct json_token *token;
|
||||
unsigned char *buf;
|
||||
size_t buflen;
|
||||
struct wpabuf *ret;
|
||||
|
||||
token = json_get_member(json, name);
|
||||
if (!token || token->type != JSON_STRING)
|
||||
return NULL;
|
||||
buf = base64_url_decode(token->string, os_strlen(token->string),
|
||||
&buflen);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
ret = wpabuf_alloc_ext_data(buf, buflen);
|
||||
if (!ret)
|
||||
os_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static const char * json_type_str(enum json_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case JSON_VALUE:
|
||||
return "VALUE";
|
||||
case JSON_OBJECT:
|
||||
return "OBJECT";
|
||||
case JSON_ARRAY:
|
||||
return "ARRAY";
|
||||
case JSON_STRING:
|
||||
return "STRING";
|
||||
case JSON_NUMBER:
|
||||
return "NUMBER";
|
||||
case JSON_BOOLEAN:
|
||||
return "BOOLEAN";
|
||||
case JSON_NULL:
|
||||
return "NULL";
|
||||
}
|
||||
return "??";
|
||||
}
|
||||
|
||||
|
||||
static void json_print_token(struct json_token *token, int depth,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
if (!token)
|
||||
return;
|
||||
len = os_strlen(buf);
|
||||
ret = os_snprintf(buf + len, buflen - len, "[%d:%s:%s]",
|
||||
depth, json_type_str(token->type),
|
||||
token->name ? token->name : "");
|
||||
if (os_snprintf_error(buflen - len, ret)) {
|
||||
buf[len] = '\0';
|
||||
return;
|
||||
}
|
||||
json_print_token(token->child, depth + 1, buf, buflen);
|
||||
json_print_token(token->sibling, depth, buf, buflen);
|
||||
}
|
||||
|
||||
|
||||
void json_print_tree(struct json_token *root, char *buf, size_t buflen)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
json_print_token(root, 1, buf, buflen);
|
||||
}
|
||||
|
||||
|
||||
void json_add_int(struct wpabuf *json, const char *name, int val)
|
||||
{
|
||||
wpabuf_printf(json, "\"%s\":%d", name, val);
|
||||
}
|
||||
|
||||
|
||||
void json_add_string(struct wpabuf *json, const char *name, const char *val)
|
||||
{
|
||||
wpabuf_printf(json, "\"%s\":\"%s\"", name, val);
|
||||
}
|
||||
|
||||
|
||||
int json_add_string_escape(struct wpabuf *json, const char *name,
|
||||
const void *val, size_t len)
|
||||
{
|
||||
char *tmp;
|
||||
size_t tmp_len = 6 * len + 1;
|
||||
|
||||
tmp = os_malloc(tmp_len);
|
||||
if (!tmp)
|
||||
return -1;
|
||||
json_escape_string(tmp, tmp_len, val, len);
|
||||
json_add_string(json, name, tmp);
|
||||
bin_clear_free(tmp, tmp_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
|
||||
size_t len)
|
||||
{
|
||||
char *b64;
|
||||
|
||||
b64 = base64_url_encode(val, len, NULL);
|
||||
if (!b64)
|
||||
return -1;
|
||||
json_add_string(json, name, b64);
|
||||
os_free(b64);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void json_start_object(struct wpabuf *json, const char *name)
|
||||
{
|
||||
if (name)
|
||||
wpabuf_printf(json, "\"%s\":", name);
|
||||
wpabuf_put_u8(json, '{');
|
||||
}
|
||||
|
||||
|
||||
void json_end_object(struct wpabuf *json)
|
||||
{
|
||||
wpabuf_put_u8(json, '}');
|
||||
}
|
||||
|
||||
|
||||
void json_start_array(struct wpabuf *json, const char *name)
|
||||
{
|
||||
if (name)
|
||||
wpabuf_printf(json, "\"%s\":", name);
|
||||
wpabuf_put_u8(json, '[');
|
||||
}
|
||||
|
||||
|
||||
void json_end_array(struct wpabuf *json)
|
||||
{
|
||||
wpabuf_put_u8(json, ']');
|
||||
}
|
||||
|
||||
|
||||
void json_value_sep(struct wpabuf *json)
|
||||
{
|
||||
wpabuf_put_u8(json, ',');
|
||||
}
|
53
components/wpa_supplicant/src/utils/json.h
Normal file
53
components/wpa_supplicant/src/utils/json.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* JavaScript Object Notation (JSON) parser (RFC7159)
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef JSON_H
|
||||
#define JSON_H
|
||||
|
||||
struct json_token {
|
||||
enum json_type {
|
||||
JSON_VALUE,
|
||||
JSON_OBJECT,
|
||||
JSON_ARRAY,
|
||||
JSON_STRING,
|
||||
JSON_NUMBER,
|
||||
JSON_BOOLEAN,
|
||||
JSON_NULL,
|
||||
} type;
|
||||
enum json_parsing_state {
|
||||
JSON_EMPTY,
|
||||
JSON_STARTED,
|
||||
JSON_WAITING_VALUE,
|
||||
JSON_COMPLETED,
|
||||
} state;
|
||||
char *name;
|
||||
char *string;
|
||||
int number;
|
||||
struct json_token *parent, *child, *sibling;
|
||||
};
|
||||
|
||||
void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len);
|
||||
struct json_token * json_parse(const char *data, size_t data_len);
|
||||
void json_free(struct json_token *json);
|
||||
struct json_token * json_get_member(struct json_token *json, const char *name);
|
||||
struct wpabuf * json_get_member_base64url(struct json_token *json,
|
||||
const char *name);
|
||||
void json_print_tree(struct json_token *root, char *buf, size_t buflen);
|
||||
void json_add_int(struct wpabuf *json, const char *name, int val);
|
||||
void json_add_string(struct wpabuf *json, const char *name, const char *val);
|
||||
int json_add_string_escape(struct wpabuf *json, const char *name,
|
||||
const void *val, size_t len);
|
||||
int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
|
||||
size_t len);
|
||||
void json_start_object(struct wpabuf *json, const char *name);
|
||||
void json_end_object(struct wpabuf *json);
|
||||
void json_start_array(struct wpabuf *json, const char *name);
|
||||
void json_end_array(struct wpabuf *json);
|
||||
void json_value_sep(struct wpabuf *json);
|
||||
|
||||
#endif /* JSON_H */
|
@@ -133,7 +133,6 @@ struct wpabuf * wpabuf_alloc(size_t len)
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)
|
||||
{
|
||||
#ifdef WPA_TRACE
|
||||
@@ -285,7 +284,7 @@ struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)
|
||||
void wpabuf_printf(struct wpabuf *buf, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
|
||||
|
Reference in New Issue
Block a user