protocomm: Added SRP6a implementation as the security version 2.

1) Rename srp component to esp_srp
2) Remove dependency on hkdf sha
3) Restructure protocomm component APIs to make them more flexible for allowing multiple security versions
4) esp_srp: convert API return type from int to esp_err_t
5) esp_srp: Formatting changes
6) Added mbedtls_gcm instead of aes_ctr

Co-authored-by: Laukik hase <laukik.hase@espressif.com>
This commit is contained in:
Aditya Patwardhan
2022-05-20 09:58:07 +05:30
committed by BOT
parent 3235206624
commit eb7ff34c89
20 changed files with 1642 additions and 158 deletions

View File

@@ -164,7 +164,7 @@ esp_err_t esp_local_ctrl_start(const esp_local_ctrl_config_t *config)
break;
}
ret = protocomm_set_security(local_ctrl_inst_ctx->pc, "esp_local_ctrl/session",
proto_sec_handle, local_ctrl_inst_ctx->config.proto_sec.pop);
proto_sec_handle, local_ctrl_inst_ctx->config.proto_sec.pop, NULL);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set session endpoint");
esp_local_ctrl_stop();

View File

@@ -1,18 +1,21 @@
set(include_dirs include/common
include/security
include/transports)
set(priv_include_dirs proto-c src/common)
set(priv_include_dirs proto-c src/common src/crypto/srp6a/include)
set(srcs
"src/common/protocomm.c"
"src/security/security0.c"
"src/security/security1.c"
"src/security/security2.c"
"proto-c/constants.pb-c.c"
"proto-c/sec0.pb-c.c"
"proto-c/sec1.pb-c.c"
"proto-c/sec2.pb-c.c"
"proto-c/session.pb-c.c"
"src/transports/protocomm_console.c"
"src/transports/protocomm_httpd.c")
"src/transports/protocomm_httpd.c"
"src/crypto/srp6a/esp_srp.c"
"src/crypto/srp6a/esp_srp_mpi.c")
if(CONFIG_BT_ENABLED)
if(CONFIG_BT_BLUEDROID_ENABLED)

View File

@@ -1,16 +1,8 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
@@ -189,13 +181,17 @@ esp_err_t protocomm_req_handle(protocomm_t *pc, const char *ep_name, uint32_t se
* - An endpoint must be bound to a valid protocomm instance,
* created using `protocomm_new()`.
* - The choice of security can be any `protocomm_security_t` instance.
* Choices `protocomm_security0` and `protocomm_security1` are readily available.
* Choices `protocomm_security0` and `protocomm_security1` and `protocomm_security2` are readily available.
*
* @param[in] pc Pointer to the protocomm instance
* @param[in] ep_name Endpoint identifier(name) string
* @param[in] sec Pointer to endpoint security instance
* @param[in] pop Pointer to proof of possession for authenticating a client
*
* @param[in] sec_params Pointer to security params (NULL if not needed)
* The pointer should contain the security params struct
* of appropriate security version.
* For protocomm security version 1 and 2
* sec_params should contain pointer to struct of type
* protocomm_security1_params_t and protocmm_security2_params_t respectively.
* @return
* - ESP_OK : Success
* - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists
@@ -205,8 +201,7 @@ esp_err_t protocomm_req_handle(protocomm_t *pc, const char *ep_name, uint32_t se
*/
esp_err_t protocomm_set_security(protocomm_t *pc, const char *ep_name,
const protocomm_security_t *sec,
const protocomm_security_pop_t *pop);
const void *sec_params);
/**
* @brief Remove endpoint security for a protocomm instance
*

View File

@@ -1,16 +1,8 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
@@ -21,9 +13,9 @@ extern "C" {
#endif
/**
* @brief Proof Of Possession for authenticating a secure session
* @brief Protocomm Security 1 parameters: Proof Of Possession
*/
typedef struct protocomm_security_pop {
typedef struct protocomm_security1_params {
/**
* Pointer to buffer containing the proof of possession data
*/
@@ -33,7 +25,35 @@ typedef struct protocomm_security_pop {
* Length (in bytes) of the proof of possession data
*/
uint16_t len;
} protocomm_security_pop_t;
} protocomm_security1_params_t;
typedef protocomm_security1_params_t protocomm_security_pop_t __attribute__((deprecated("Use protocomm_security1_params_t instead")));
/**
* @brief Protocomm Security 2 parameters: Salt and Verifier
*
*/
typedef struct protocomm_security2_params {
/**
* Pointer to the buffer containing the salt
*/
const char *salt;
/**
* Length (in bytes) of the salt
*/
uint16_t salt_len;
/**
* Pointer to the buffer containing the verifier
*/
const char *verifier;
/**
* Length (in bytes) of the verifier
*/
uint16_t verifier_len;
} protocomm_security2_params_t;
typedef void * protocomm_security_handle_t;
@@ -80,7 +100,7 @@ typedef struct protocomm_security {
* request and establishing secure session
*/
esp_err_t (*security_req_handler)(protocomm_security_handle_t handle,
const protocomm_security_pop_t *pop,
const void *sec_params,
uint32_t session_id,
const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen,
@@ -92,7 +112,7 @@ typedef struct protocomm_security {
esp_err_t (*encrypt)(protocomm_security_handle_t handle,
uint32_t session_id,
const uint8_t *inbuf, ssize_t inlen,
uint8_t *outbuf, ssize_t *outlen);
uint8_t **outbuf, ssize_t *outlen);
/**
* Function which implements the decryption algorithm
@@ -100,7 +120,7 @@ typedef struct protocomm_security {
esp_err_t (*decrypt)(protocomm_security_handle_t handle,
uint32_t session_id,
const uint8_t *inbuf, ssize_t inlen,
uint8_t *outbuf, ssize_t *outlen);
uint8_t **outbuf, ssize_t *outlen);
} protocomm_security_t;
#ifdef __cplusplus

View File

@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <protocomm_security.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Protocomm security version 2 implementation
*
* This is a full fledged security implementation using
* key exchange based on SRP6a (RFC 5054)
* and AES-GCM encryption/decryption
*/
extern const protocomm_security_t protocomm_security2;
#ifdef __cplusplus
}
#endif

View File

@@ -53,10 +53,9 @@ void protocomm_delete(protocomm_t *pc)
if (pc->sec && pc->sec->cleanup) {
pc->sec->cleanup(pc->sec_inst);
}
if (pc->pop) {
free(pc->pop);
if (pc->sec_params) {
free(pc->sec_params);
}
free(pc);
}
@@ -199,14 +198,9 @@ esp_err_t protocomm_req_handle(protocomm_t *pc, const char *ep_name, uint32_t se
} else if (ep->flag & REQ_EP) {
if (pc->sec && pc->sec->decrypt) {
/* Decrypt the data first */
uint8_t *dec_inbuf = (uint8_t *) malloc(inlen);
if (!dec_inbuf) {
ESP_LOGE(TAG, "Failed to allocate decrypt buf len %d", inlen);
return ESP_ERR_NO_MEM;
}
ssize_t dec_inbuf_len = inlen;
ret = pc->sec->decrypt(pc->sec_inst, session_id, inbuf, inlen, dec_inbuf, &dec_inbuf_len);
ssize_t dec_inbuf_len = 0;
uint8_t *dec_inbuf = NULL;
ret = pc->sec->decrypt(pc->sec_inst, session_id, inbuf, inlen, &dec_inbuf, &dec_inbuf_len);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Decryption of response failed for endpoint %s", ep_name);
free(dec_inbuf);
@@ -229,17 +223,10 @@ esp_err_t protocomm_req_handle(protocomm_t *pc, const char *ep_name, uint32_t se
/* We don't need decrypted data anymore */
free(dec_inbuf);
/* Encrypt response to be sent back */
uint8_t *enc_resp = (uint8_t *) malloc(plaintext_resp_len);
if (!enc_resp) {
ESP_LOGE(TAG, "Failed to allocate encrypt buf len %d", plaintext_resp_len);
free(plaintext_resp);
return ESP_ERR_NO_MEM;
}
ssize_t enc_resp_len = plaintext_resp_len;
uint8_t *enc_resp = NULL;
ssize_t enc_resp_len = 0;
ret = pc->sec->encrypt(pc->sec_inst, session_id, plaintext_resp, plaintext_resp_len,
enc_resp, &enc_resp_len);
&enc_resp, &enc_resp_len);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Encryption of response failed for endpoint %s", ep_name);
@@ -278,7 +265,7 @@ static int protocomm_common_security_handler(uint32_t session_id,
if (pc->sec && pc->sec->security_req_handler) {
return pc->sec->security_req_handler(pc->sec_inst,
pc->pop, session_id,
pc->sec_params, session_id,
inbuf, inlen,
outbuf, outlen,
priv_data);
@@ -289,7 +276,7 @@ static int protocomm_common_security_handler(uint32_t session_id,
esp_err_t protocomm_set_security(protocomm_t *pc, const char *ep_name,
const protocomm_security_t *sec,
const protocomm_security_pop_t *pop)
const void *sec_params)
{
if ((pc == NULL) || (ep_name == NULL) || (sec == NULL)) {
return ESP_ERR_INVALID_ARG;
@@ -317,22 +304,42 @@ esp_err_t protocomm_set_security(protocomm_t *pc, const char *ep_name,
}
pc->sec = sec;
if (pop) {
pc->pop = malloc(sizeof(protocomm_security_pop_t));
if (pc->pop == NULL) {
ESP_LOGE(TAG, "Error allocating Proof of Possession");
/* sec params is not needed and thus checked in case of security 0 */
if (pc->sec->ver == 1) {
if (sec_params) {
pc->sec_params = calloc(1, sizeof(protocomm_security1_params_t));
if (pc->sec_params == NULL) {
ESP_LOGE(TAG, "Error allocating memory for security1 params");
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
memcpy((void *)pc->sec_params, sec_params, sizeof(protocomm_security1_params_t));
}
} else if (pc->sec->ver == 2) {
if (sec_params) {
pc->sec_params = calloc(1, sizeof(protocomm_security2_params_t));
if (pc->sec_params == NULL) {
ESP_LOGE(TAG, "Error allocating memory for security2 params");
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
memcpy((void *)pc->sec_params, sec_params, sizeof(protocomm_security2_params_t));
} else {
ESP_LOGE(TAG, "Security params cannot be null");
ret = ESP_ERR_INVALID_ARG;
goto cleanup;
}
}
return ESP_OK;
cleanup:
if (pc->sec && pc->sec->cleanup) {
pc->sec->cleanup(pc->sec_inst);
pc->sec_inst = NULL;
pc->sec = NULL;
}
protocomm_remove_endpoint(pc, ep_name);
return ESP_ERR_NO_MEM;
}
memcpy((void *)pc->pop, pop, sizeof(protocomm_security_pop_t));
}
return ESP_OK;
return ret;
}
esp_err_t protocomm_unset_security(protocomm_t *pc, const char *ep_name)
@@ -347,9 +354,9 @@ esp_err_t protocomm_unset_security(protocomm_t *pc, const char *ep_name)
pc->sec = NULL;
}
if (pc->pop) {
free(pc->pop);
pc->pop = NULL;
if (pc->sec_params) {
free(pc->sec_params);
pc->sec_params = NULL;
}
return protocomm_remove_endpoint(pc, ep_name);

View File

@@ -1,16 +1,8 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
@@ -68,8 +60,8 @@ struct protocomm {
/* Handle to the security layer instance */
protocomm_security_handle_t sec_inst;
/* Pointer to proof of possession object */
protocomm_security_pop_t *pop;
/* Pointer to security params */
void *sec_params;
/* Head of the singly linked list for storing endpoint handlers */
SLIST_HEAD(eptable_t, protocomm_ep) endpoints;

View File

@@ -0,0 +1,546 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// This file contains SRP6a implementation based on RFC 5054
#include <string.h>
#include "esp_log.h"
#include "esp_err.h"
#include <mbedtls/sha512.h>
#include "esp_srp_mpi.h"
#include "esp_srp.h"
#define SHA512_HASH_SZ 64
static const char *TAG = "srp6a";
static void hexdump_mpi(const char *name, esp_mpi_t *bn)
{
int len = 0;
char *str = esp_mpi_to_bin(bn, &len);
if (str) {
ESP_LOGD(TAG, "%s ->", name);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, str, len, ESP_LOG_DEBUG);
free(str);
}
}
/************************* SRP Stuff *************************/
static const char N_3072[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static const char g_3072[] = { 5 };
esp_err_t esp_srp_init(esp_srp_handle_t *hd, esp_ng_type_t ng)
{
if (hd->allocated) {
esp_srp_free(hd);
}
memset(hd, 0, sizeof(*hd));
hd->allocated = 1;
hd->ctx = esp_mpi_ctx_new();
if (! hd->ctx) {
goto error;
}
if (ng != ESP_NG_3072) {
goto error;
}
hd->n = esp_mpi_new_from_bin(N_3072, sizeof(N_3072));
hd->bytes_n = N_3072;
hd->len_n = sizeof(N_3072);
if (! hd->n) {
goto error;
}
hd->g = esp_mpi_new_from_bin(g_3072, sizeof(g_3072));
hd->bytes_g = g_3072;
hd->len_g = sizeof(g_3072);
if (! hd->g) {
goto error;
}
hd->type = ng;
return ESP_OK;
error:
esp_srp_free(hd);
return ESP_FAIL;
}
void esp_srp_free(esp_srp_handle_t *hd)
{
if (hd->allocated != 1) {
return;
}
if (hd->ctx) {
esp_mpi_ctx_free(hd->ctx);
}
if (hd->n) {
esp_mpi_free(hd->n);
}
if (hd->g) {
esp_mpi_free(hd->g);
}
if (hd->s) {
esp_mpi_free(hd->s);
}
if (hd->bytes_s) {
free(hd->bytes_s);
}
if (hd->v) {
esp_mpi_free(hd->v);
}
if (hd->B) {
esp_mpi_free(hd->B);
}
if (hd->bytes_B) {
free(hd->bytes_B);
}
if (hd->b) {
esp_mpi_free(hd->b);
}
if (hd->A) {
esp_mpi_free(hd->A);
}
if (hd->bytes_A) {
free(hd->bytes_A);
}
if (hd->session_key) {
free(hd->session_key);
}
memset(hd, 0, sizeof(*hd));
}
static esp_mpi_t *calculate_x(char *bytes_salt, int salt_len, const char *username, int username_len, const char *pass, int pass_len)
{
unsigned char digest[SHA512_HASH_SZ];
mbedtls_sha512_context ctx;
ESP_LOGD(TAG, "Username: %s | Passphrase: %s | Passphrase length: %d", username, pass, pass_len);
mbedtls_sha512_init(&ctx);
mbedtls_sha512_starts(&ctx, 0);
mbedtls_sha512_update(&ctx, (unsigned char *)username, username_len);
mbedtls_sha512_update(&ctx, (unsigned char *)":", 1);
mbedtls_sha512_update(&ctx, (unsigned char *)pass, pass_len);
mbedtls_sha512_finish(&ctx, digest);
mbedtls_sha512_init(&ctx);
mbedtls_sha512_starts(&ctx, 0);
mbedtls_sha512_update(&ctx, (unsigned char *)bytes_salt, salt_len);
mbedtls_sha512_update(&ctx, digest, sizeof(digest));
mbedtls_sha512_finish(&ctx, digest);
mbedtls_sha512_free(&ctx);
return esp_mpi_new_from_bin((char *)digest, sizeof(digest));
}
static esp_mpi_t *calculate_padded_hash(esp_srp_handle_t *hd, const char *a, int len_a, const char *b, int len_b)
{
unsigned char digest[SHA512_HASH_SZ];
mbedtls_sha512_context ctx;
int pad_len;
char *s = NULL;
if (len_a > len_b) {
pad_len = hd->len_n - len_b;
} else {
pad_len = hd->len_n - len_a;
}
if (pad_len) {
s = malloc(pad_len);
if (s) {
memset(s, 0, pad_len);
}
}
mbedtls_sha512_init(&ctx);
mbedtls_sha512_starts(&ctx, 0);
/* PAD (a) */
if (s && (len_a != hd->len_n)) {
mbedtls_sha512_update(&ctx, (unsigned char *)s, hd->len_n - len_a);
}
mbedtls_sha512_update(&ctx, (unsigned char *)a, len_a);
/* PAD (b) */
if (s && (len_b != hd->len_n)) {
mbedtls_sha512_update(&ctx, (unsigned char *)s, hd->len_n - len_b);
}
mbedtls_sha512_update(&ctx, (unsigned char *)b, len_b);
mbedtls_sha512_finish(&ctx, digest);
mbedtls_sha512_free(&ctx);
if (s) {
free(s);
}
return esp_mpi_new_from_bin((char *)digest, sizeof(digest));
}
/* k = SHA (N, PAD(g))
*
* https://tools.ietf.org/html/draft-ietf-tls-srp-08
*/
static esp_mpi_t *calculate_k(esp_srp_handle_t *hd)
{
return calculate_padded_hash(hd, hd->bytes_n, hd->len_n, hd->bytes_g, hd->len_g);
}
static esp_mpi_t *calculate_u(esp_srp_handle_t *hd, char *A, int len_A)
{
return calculate_padded_hash(hd, A, len_A, hd->bytes_B, hd->len_B);
}
esp_err_t __esp_srp_srv_pubkey(esp_srp_handle_t *hd, char **bytes_B, int *len_B)
{
esp_mpi_t *k = calculate_k(hd);
esp_mpi_t *kv = NULL;
esp_mpi_t *gb = NULL;
if (!k) {
goto error;
}
hexdump_mpi("k", k);
hd->b = esp_mpi_new();
if (!hd->b) {
goto error;
}
esp_mpi_get_rand(hd->b, 256, -1, 0);
hexdump_mpi("b", hd->b);
/* B = kv + g^b */
kv = esp_mpi_new();
gb = esp_mpi_new();
hd->B = esp_mpi_new();
if (!kv || !gb || ! hd->B) {
goto error;
}
esp_mpi_a_mul_b_mod_c(kv, k, hd->v, hd->n, hd->ctx);
esp_mpi_a_exp_b_mod_c(gb, hd->g, hd->b, hd->n, hd->ctx);
esp_mpi_a_add_b_mod_c(hd->B, kv, gb, hd->n, hd->ctx);
hd->bytes_B = esp_mpi_to_bin(hd->B, len_B);
hd->len_B = *len_B;
*bytes_B = hd->bytes_B;
esp_mpi_free(k);
esp_mpi_free(kv);
esp_mpi_free(gb);
return ESP_OK;
error:
if (k) {
esp_mpi_free(k);
}
if (kv) {
esp_mpi_free(kv);
}
if (gb) {
esp_mpi_free(gb);
}
if (hd->B) {
esp_mpi_free(hd->B);
hd->B = NULL;
}
if (hd->b) {
esp_mpi_free(hd->b);
hd->b = NULL;
}
return ESP_FAIL;
}
esp_err_t esp_srp_srv_pubkey(esp_srp_handle_t *hd, const char *username, int username_len, const char *pass, int pass_len, int salt_len,
char **bytes_B, int *len_B, char **bytes_salt)
{
/* Get Salt */
int str_salt_len;
esp_mpi_t *x = NULL;
hd->s = esp_mpi_new();
if (! hd->s) {
goto error;
}
esp_mpi_get_rand(hd->s, 8 * salt_len, -1, 0);
*bytes_salt = esp_mpi_to_bin(hd->s, &str_salt_len);
if (! *bytes_salt) {
goto error;
}
hd->bytes_s = *bytes_salt;
hd->len_s = salt_len;
ESP_LOGD(TAG, "Salt ->");
ESP_LOG_BUFFER_HEX_LEVEL(TAG, *bytes_salt, str_salt_len, ESP_LOG_DEBUG);
/* Calculate X which is simply a hash for all these things */
x = calculate_x(*bytes_salt, str_salt_len, username, username_len, pass, pass_len);
if (! x) {
goto error;
}
hexdump_mpi("x", x);
/* v = g^x % N */
hd->v = esp_mpi_new();
if (! hd->v) {
goto error;
}
esp_mpi_a_exp_b_mod_c(hd->v, hd->g, x, hd->n, hd->ctx);
hexdump_mpi("Verifier", hd->v);
if (__esp_srp_srv_pubkey(hd, bytes_B, len_B) < 0 ) {
goto error;
}
esp_mpi_free(x);
return ESP_OK;
error:
if (hd->s) {
esp_mpi_free(hd->s);
hd->s = NULL;
}
if (*bytes_salt) {
free(*bytes_salt);
*bytes_salt = NULL;
hd->bytes_s = NULL;
hd->len_s = 0;
}
if (x) {
esp_mpi_free(x);
x = NULL;
}
if (hd->v) {
esp_mpi_free(hd->v);
hd->v = NULL;
}
return ESP_FAIL;
}
esp_err_t esp_srp_srv_pubkey_from_salt_verifier(esp_srp_handle_t *hd, char **bytes_B, int *len_B)
{
return __esp_srp_srv_pubkey(hd, bytes_B, len_B);
}
esp_err_t esp_srp_set_salt_verifier(esp_srp_handle_t *hd, const char *salt, int salt_len,
const char *verifier, int verifier_len)
{
hd->bytes_s = malloc(salt_len);
if (!hd->bytes_s) {
goto error;
}
memcpy(hd->bytes_s, salt, salt_len);
hd->len_s = salt_len;
hd->s = esp_mpi_new_from_bin(salt, salt_len);
if (!hd->s) {
goto error;
}
hd->v = esp_mpi_new_from_bin(verifier, verifier_len);
if (!hd->v) {
goto error;
}
return ESP_OK;
error:
if (hd->bytes_s) {
free(hd->bytes_s);
hd->bytes_s = NULL;
hd->len_s = 0;
}
if (hd->s) {
esp_mpi_free(hd->s);
hd->s = NULL;
}
if (hd->v) {
esp_mpi_free(hd->v);
hd->v = NULL;
}
return ESP_FAIL;
}
esp_err_t esp_srp_get_session_key(esp_srp_handle_t *hd, char *bytes_A, int len_A, char **bytes_key, int *len_key)
{
esp_mpi_t *u = NULL;
esp_mpi_t *vu = NULL;
esp_mpi_t *avu = NULL;
esp_mpi_t *S = NULL;
char *bytes_S;
int len_S;
u = vu = avu = S = NULL;
bytes_S = NULL;
hd->bytes_A = malloc(len_A);
if (! hd->bytes_A) {
goto error;
}
memcpy(hd->bytes_A, bytes_A, len_A);
hd->len_A = len_A;
hd->A = esp_mpi_new_from_bin(bytes_A, len_A);
if (! hd->A) {
goto error;
}
u = calculate_u(hd, bytes_A, len_A);
if (! u) {
goto error;
}
hexdump_mpi("u", u);
/* S = (A v^u)^b */
vu = esp_mpi_new();
avu = esp_mpi_new();
S = esp_mpi_new();
if (!vu || !avu || !S ) {
goto error;
}
esp_mpi_a_exp_b_mod_c(vu, hd->v, u, hd->n, hd->ctx);
esp_mpi_a_mul_b_mod_c(avu, hd->A, vu, hd->n, hd->ctx);
esp_mpi_a_exp_b_mod_c(S, avu, hd->b, hd->n, hd->ctx);
hexdump_mpi("S", S);
bytes_S = esp_mpi_to_bin(S, &len_S);
hd->session_key = malloc(SHA512_HASH_SZ);
if (!hd->session_key || ! bytes_S) {
goto error;
}
mbedtls_sha512((unsigned char *)bytes_S, len_S, (unsigned char *)hd->session_key, 0);
*bytes_key = hd->session_key;
*len_key = SHA512_HASH_SZ;
free(bytes_S);
esp_mpi_free(vu);
esp_mpi_free(avu);
esp_mpi_free(S);
esp_mpi_free(u);
return ESP_OK;
error:
if (bytes_S) {
free(bytes_S);
}
if (vu) {
esp_mpi_free(vu);
}
if (avu) {
esp_mpi_free(avu);
}
if (S) {
esp_mpi_free(S);
}
if (u) {
esp_mpi_free(u);
}
if (hd->session_key) {
free(hd->session_key);
hd->session_key = NULL;
}
if (hd->A) {
esp_mpi_free(hd->A);
hd->A = NULL;
}
if (hd->bytes_A) {
free(hd->bytes_A);
hd->bytes_A = NULL;
}
return ESP_FAIL;
}
esp_err_t esp_srp_exchange_proofs(esp_srp_handle_t *hd, char *username, uint16_t username_len, char *bytes_user_proof, char *bytes_host_proof)
{
/* First calculate M */
unsigned char hash_n[SHA512_HASH_SZ];
unsigned char hash_g[SHA512_HASH_SZ];
unsigned char hash_n_xor_g[SHA512_HASH_SZ];
int i;
unsigned char hash_I[SHA512_HASH_SZ];
mbedtls_sha512((unsigned char *)username, username_len, (unsigned char *)hash_I, 0);
mbedtls_sha512((unsigned char *)hd->bytes_n, hd->len_n, (unsigned char *)hash_n, 0);
int pad_len = hd->len_n - hd->len_g;
char *s = calloc(pad_len, sizeof(char));
if (!s) {
return ESP_ERR_NO_MEM;
}
mbedtls_sha512_context ctx;
mbedtls_sha512_init(&ctx);
mbedtls_sha512_starts(&ctx, 0);
mbedtls_sha512_update(&ctx, (unsigned char *)s, pad_len);
mbedtls_sha512_update(&ctx, (unsigned char *)hd->bytes_g, hd->len_g);
mbedtls_sha512_finish(&ctx, hash_g);
mbedtls_sha512_free(&ctx);
for (i = 0; i < SHA512_HASH_SZ; i++) {
hash_n_xor_g[i] = hash_n[i] ^ hash_g[i];
}
unsigned char digest[SHA512_HASH_SZ];
mbedtls_sha512_init(&ctx);
mbedtls_sha512_starts(&ctx, 0);
mbedtls_sha512_update(&ctx, hash_n_xor_g, SHA512_HASH_SZ);
mbedtls_sha512_update(&ctx, hash_I, SHA512_HASH_SZ);
mbedtls_sha512_update(&ctx, (unsigned char *)hd->bytes_s, hd->len_s);
mbedtls_sha512_update(&ctx, (unsigned char *)hd->bytes_A, hd->len_A);
mbedtls_sha512_update(&ctx, (unsigned char *)hd->bytes_B, hd->len_B);
mbedtls_sha512_update(&ctx, (unsigned char *)hd->session_key, SHA512_HASH_SZ);
mbedtls_sha512_finish(&ctx, digest);
mbedtls_sha512_free(&ctx);
ESP_LOGD(TAG, "M ->");
ESP_LOG_BUFFER_HEX_LEVEL(TAG, (char *)digest, sizeof(digest), ESP_LOG_DEBUG);
if (memcmp(bytes_user_proof, digest, SHA512_HASH_SZ) != 0) {
return ESP_FAIL;
}
/* M is now validated, let's proceed to H(AMK) */
mbedtls_sha512_init(&ctx);
mbedtls_sha512_starts(&ctx, 0);
mbedtls_sha512_update(&ctx, (unsigned char *)hd->bytes_A, hd->len_A);
mbedtls_sha512_update(&ctx, digest, SHA512_HASH_SZ);
mbedtls_sha512_update(&ctx, (unsigned char *)hd->session_key, SHA512_HASH_SZ);
mbedtls_sha512_finish(&ctx, (unsigned char *)bytes_host_proof);
mbedtls_sha512_free(&ctx);
ESP_LOGD(TAG, "AMK ->");
ESP_LOG_BUFFER_HEX_LEVEL(TAG, (char *)bytes_host_proof, SHA512_HASH_SZ, ESP_LOG_DEBUG);
if (s) {
free(s);
}
return ESP_OK;
}

View File

@@ -0,0 +1,148 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_srp_mpi.h"
esp_mpi_t *esp_mpi_new(void)
{
esp_mpi_t *a = (esp_mpi_t *)malloc(sizeof (esp_mpi_t));
if (!a) {
return NULL;
}
mbedtls_mpi_init(a);
return a;
}
esp_mpi_t *esp_mpi_new_from_hex(const char *hex)
{
esp_mpi_t *a = esp_mpi_new();
if (!a) {
return NULL;
}
int ret = mbedtls_mpi_read_string(a, 16, hex);
if (ret != 0) {
printf("mbedtls_mpi_read_string() failed, returned %x\n", ret);
return NULL;
}
return a;
}
esp_mpi_t *esp_mpi_new_from_bin(const char *str, int str_len)
{
esp_mpi_t *a = esp_mpi_new();
if (!a) {
return NULL;
}
int ret = mbedtls_mpi_read_binary(a, (unsigned char *)str, str_len);
if (ret != 0) {
printf("mbedtls_mpi_read_binary() failed, returned %x\n", ret);
return NULL;
}
return a;
}
void esp_mpi_free(esp_mpi_t *bn)
{
if (bn) {
mbedtls_mpi_free(bn);
free(bn);
}
}
esp_mpi_ctx_t *esp_mpi_ctx_new(void)
{
esp_mpi_t *bn = esp_mpi_new();
return ( esp_mpi_ctx_t *)bn;
}
void esp_mpi_ctx_free(esp_mpi_ctx_t *ctx)
{
esp_mpi_free((esp_mpi_t *)ctx);
}
unsigned int esp_mpi_sizeof(esp_mpi_t *bn)
{
return mbedtls_mpi_size(bn);
}
char *esp_mpi_to_bin(esp_mpi_t *bn, int *len)
{
*len = esp_mpi_sizeof(bn);
char *p = malloc(*len);
if (!p) {
return NULL;
}
int ret = mbedtls_mpi_write_binary(bn, (unsigned char *)p, *len);
if (ret != 0) {
printf("mbedtls_mpi_read_string() failed, returned %x\n", ret);
return NULL;
}
return p;
}
int esp_get_random(void *ctx, unsigned char *data, size_t len)
{
(void) ctx;
esp_fill_random(data, len);
return 0;
}
int esp_mpi_get_rand(esp_mpi_t *bn, int bits, int top, int bottom)
{
(void) top;
(void) bottom;
return mbedtls_mpi_fill_random(bn, bits / 8, esp_get_random, NULL);
}
int esp_mpi_a_exp_b_mod_c(esp_mpi_t *result, esp_mpi_t *a, esp_mpi_t *b, esp_mpi_t *c, esp_mpi_ctx_t *ctx)
{
return mbedtls_mpi_exp_mod(result, a, b, c, (esp_mpi_t *) ctx);
}
int esp_mpi_a_mul_b_mod_c(esp_mpi_t *result, esp_mpi_t *a, esp_mpi_t *b, esp_mpi_t *c, esp_mpi_ctx_t *ctx)
{
(void) ctx;
int res;
mbedtls_mpi t;
mbedtls_mpi_init(&t);
res = mbedtls_mpi_mul_mpi(&t, a, b);
if (res != 0) {
printf("mbedtls_mpi_mul_mpi(), returned %x\n", res);
return res;
}
res = mbedtls_mpi_mod_mpi(result, &t, c);
if (res != 0) {
printf("mbedtls_mpi_mod_mpi() failed, returned %x\n", res);
return res;
}
mbedtls_mpi_free(&t);
return res;
}
int esp_mpi_a_add_b_mod_c(esp_mpi_t *result, esp_mpi_t *a, esp_mpi_t *b, esp_mpi_t *c, esp_mpi_ctx_t *ctx)
{
(void) ctx;
int res;
mbedtls_mpi t;
mbedtls_mpi_init(&t);
res = mbedtls_mpi_add_mpi(&t, a, b);
if (res != 0) {
printf("mbedtls_mpi_add_mpi() failed, returned %x\n", res);
return res;
}
res = mbedtls_mpi_mod_mpi(result, &t, c);
if (res != 0) {
printf("mbedtls_mpi_mod_mpi(), returned %x\n", res);
return res;
}
mbedtls_mpi_free(&t);
return res;
}

View File

@@ -0,0 +1,103 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "esp_srp_mpi.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
/* SRP specific:
* N = 3072 bit large safe prime,
* g = generator */
ESP_NG_3072 = 0,
} esp_ng_type_t;
typedef struct esp_srp_handle {
int allocated;
esp_ng_type_t type;
esp_mpi_ctx_t *ctx;
/* N
* the bytes_n simply points to the static array
*/
esp_mpi_t *n;
const char *bytes_n;
int len_n;
/* g
* the bytes_g simply points to the static array
*/
esp_mpi_t *g;
const char *bytes_g;
int len_g;
/* Salt */
esp_mpi_t *s;
char *bytes_s;
int len_s;
/* Verifier */
esp_mpi_t *v;
/* B */
esp_mpi_t *B;
char *bytes_B;
int len_B;
/* b */
esp_mpi_t *b;
/* A */
esp_mpi_t *A;
char *bytes_A;
int len_A;
/* K - session key*/
char *session_key;
} esp_srp_handle_t;
int esp_srp_init(esp_srp_handle_t *hd, esp_ng_type_t ng);
void esp_srp_free(esp_srp_handle_t *hd);
/* Returns B (pub key) and salt
*
* *bytes_B MUST NOT BE FREED BY THE CALLER
* *bytes_salt MUST NOT BE FREE BY THE CALLER
*
*/
esp_err_t esp_srp_srv_pubkey(esp_srp_handle_t *hd, const char *username, int username_len, const char *pass, int pass_len, int salt_len,
char **bytes_B, int *len_B, char **bytes_salt);
/* Set the Salt and Verifier pre-generated for a given password.
* This should be used only if the actual password is not available.
* The public key can then be generated using esp_srp_srv_pubkey_from_salt_verifier()
* and not esp_srp_srv_pubkey()
*/
esp_err_t esp_srp_set_salt_verifier(esp_srp_handle_t *hd, const char *salt, int salt_len,
const char *verifier, int verifier_len);
/* Returns B (pub key) when the salt and verifier are set using esp_srp_set_salt_verifier()
*
* *bytes_B MUST NOT BE FREED BY THE CALLER
*/
esp_err_t esp_srp_srv_pubkey_from_salt_verifier(esp_srp_handle_t *hd, char **bytes_B, int *len_B);
/* Returns bytes_key
* *bytes_key MUST NOT BE FREED BY THE CALLER
*/
esp_err_t esp_srp_get_session_key(esp_srp_handle_t *hd, char *bytes_A, int len_A, char **bytes_key, int *len_key);
/* Exchange proofs
* Returns 1 if user's proof is ok. Also 1 when is returned, bytes_host_proof contains our proof.
*
* bytes_user_proof is parameter in
* bytes_host_proof is parameter out (should be SHA512_DIGEST_LENGTH) bytes in size
*/
esp_err_t esp_srp_exchange_proofs(esp_srp_handle_t *hd, char *username, uint16_t username_len, char *bytes_user_proof, char *bytes_host_proof);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include "mbedtls/bignum.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "esp_random.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef mbedtls_mpi esp_mpi_t;
typedef esp_mpi_t esp_mpi_ctx_t;
esp_mpi_t *esp_mpi_new(void);
esp_mpi_t *esp_mpi_new_from_hex(const char *hex);
esp_mpi_t *esp_mpi_new_from_bin(const char *str, int str_len);
void esp_mpi_free(esp_mpi_t *bn);
esp_mpi_ctx_t *esp_mpi_ctx_new(void);
void esp_mpi_ctx_free(esp_mpi_ctx_t *ctx);
unsigned int esp_mpi_sizeof(esp_mpi_t *bn);
char *esp_mpi_to_bin(esp_mpi_t *bn, int *len);
int esp_get_random(void *ctx, unsigned char *data, size_t len);
int esp_mpi_get_rand(esp_mpi_t *bn, int bits, int top, int bottom);
int esp_mpi_a_exp_b_mod_c(esp_mpi_t *result, esp_mpi_t *a, esp_mpi_t *b, esp_mpi_t *c, esp_mpi_ctx_t *ctx);
int esp_mpi_a_mul_b_mod_c(esp_mpi_t *result, esp_mpi_t *a, esp_mpi_t *b, esp_mpi_t *c, esp_mpi_ctx_t *ctx);
int esp_mpi_a_add_b_mod_c(esp_mpi_t *result, esp_mpi_t *a, esp_mpi_t *b, esp_mpi_t *c, esp_mpi_ctx_t *ctx);
#ifdef __cplusplus
}
#endif

View File

@@ -1,16 +1,8 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
@@ -29,8 +21,7 @@
static const char* TAG = "security0";
static esp_err_t sec0_session_setup(uint32_t session_id,
SessionData *req, SessionData *resp,
const protocomm_security_pop_t *pop)
SessionData *req, SessionData *resp)
{
Sec0Payload *out = (Sec0Payload *) malloc(sizeof(Sec0Payload));
S0SessionResp *s0resp = (S0SessionResp *) malloc(sizeof(S0SessionResp));
@@ -66,7 +57,7 @@ static void sec0_session_setup_cleanup(uint32_t session_id, SessionData *resp)
}
static esp_err_t sec0_req_handler(protocomm_security_handle_t handle,
const protocomm_security_pop_t *pop,
const void *sec_params,
uint32_t session_id,
const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen,
@@ -88,7 +79,7 @@ static esp_err_t sec0_req_handler(protocomm_security_handle_t handle,
}
session_data__init(&resp);
ret = sec0_session_setup(session_id, req, &resp, pop);
ret = sec0_session_setup(session_id, req, &resp);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Session setup error %d", ret);
session_data__free_unpacked(req, NULL);

View File

@@ -37,7 +37,6 @@ which are undefined if the following flag is not defined */
#include <mbedtls/error.h>
#include <mbedtls/constant_time.h>
#include <ssl_misc.h>
#include <mbedtls/constant_time.h>
#include <protocomm_security.h>
#include <protocomm_security1.h>
@@ -193,7 +192,7 @@ static esp_err_t sec1_new_session(protocomm_security_handle_t handle, uint32_t s
static esp_err_t handle_session_command0(session_t *cur_session,
uint32_t session_id,
SessionData *req, SessionData *resp,
const protocomm_security_pop_t *pop)
const protocomm_security1_params_t *pop)
{
ESP_LOGD(TAG, "Request to handle setup0_command");
Sec1Payload *in = (Sec1Payload *) req->sec1;
@@ -375,7 +374,7 @@ exit_cmd0:
static esp_err_t sec1_session_setup(session_t *cur_session,
uint32_t session_id,
SessionData *req, SessionData *resp,
const protocomm_security_pop_t *pop)
const protocomm_security1_params_t *pop)
{
Sec1Payload *in = (Sec1Payload *) req->sec1;
esp_err_t ret;
@@ -502,17 +501,13 @@ static esp_err_t sec1_cleanup(protocomm_security_handle_t handle)
static esp_err_t sec1_decrypt(protocomm_security_handle_t handle,
uint32_t session_id,
const uint8_t *inbuf, ssize_t inlen,
uint8_t *outbuf, ssize_t *outlen)
uint8_t **outbuf, ssize_t *outlen)
{
session_t *cur_session = (session_t *) handle;
if (!cur_session) {
return ESP_ERR_INVALID_ARG;
}
if (*outlen < inlen) {
return ESP_ERR_INVALID_ARG;
}
if (!cur_session || cur_session->id != session_id) {
ESP_LOGE(TAG, "Session with ID %d not found", session_id);
return ESP_ERR_INVALID_STATE;
@@ -524,8 +519,14 @@ static esp_err_t sec1_decrypt(protocomm_security_handle_t handle,
}
*outlen = inlen;
*outbuf = (uint8_t *) malloc(*outlen);
if (!*outbuf) {
ESP_LOGE(TAG, "Failed to allocate encrypt/decrypt buf len %d", *outlen);
return ESP_ERR_NO_MEM;
}
int ret = mbedtls_aes_crypt_ctr(&cur_session->ctx_aes, inlen, &cur_session->nc_off,
cur_session->rand, cur_session->stb, inbuf, outbuf);
cur_session->rand, cur_session->stb, inbuf, *outbuf);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_aes_crypt_ctr with error code : %d", ret);
return ESP_FAIL;
@@ -534,7 +535,7 @@ static esp_err_t sec1_decrypt(protocomm_security_handle_t handle,
}
static esp_err_t sec1_req_handler(protocomm_security_handle_t handle,
const protocomm_security_pop_t *pop,
const void *sec_params,
uint32_t session_id,
const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen,
@@ -567,7 +568,7 @@ static esp_err_t sec1_req_handler(protocomm_security_handle_t handle,
}
session_data__init(&resp);
ret = sec1_session_setup(cur_session, session_id, req, &resp, pop);
ret = sec1_session_setup(cur_session, session_id, req, &resp, (protocomm_security1_params_t *) sec_params);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Session setup error %d", ret);
session_data__free_unpacked(req, NULL);

View File

@@ -0,0 +1,539 @@
/*
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <esp_err.h>
#include <esp_log.h>
#include <esp_check.h>
#include <mbedtls/gcm.h>
#include <mbedtls/error.h>
#include <esp_random.h>
#include <protocomm_security.h>
#include <protocomm_security2.h>
#include "session.pb-c.h"
#include "sec2.pb-c.h"
#include "constants.pb-c.h"
#include "esp_srp.h"
static const char *TAG = "security2";
#define SALT_LEN (16)
#define PUBLIC_KEY_LEN (384)
#define CLIENT_PROOF_LEN (64)
#define AES_GCM_KEY_LEN (256)
#define AES_GCM_IV_SIZE (16)
#define AES_GCM_TAG_LEN (16)
#define SESSION_STATE_CMD0 0 /* Session is not setup: Initial State*/
#define SESSION_STATE_CMD1 1 /* Session is not setup: Cmd0 done */
#define SESSION_STATE_DONE 2 /* Session setup successful */
typedef struct session {
/* Session data */
uint32_t id;
uint8_t state;
/* Currently fixing the salt length to 16, we may keep it flexible */
char *username;
uint16_t username_len;
char *salt;
uint16_t salt_len;
char *verifier;
uint16_t verifier_len;
char *client_pubkey;
uint16_t client_pubkey_len;
char *session_key;
uint16_t session_key_len;
uint8_t iv[AES_GCM_IV_SIZE];
/* mbedtls context data for AES-GCM */
mbedtls_gcm_context ctx_gcm;
esp_srp_handle_t *srp_hd;
} session_t;
static void hexdump(const char *msg, char *buf, int len)
{
ESP_LOGD(TAG, "%s ->", msg);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, buf, len, ESP_LOG_DEBUG);
}
static esp_err_t sec2_new_session(protocomm_security_handle_t handle, uint32_t session_id);
static esp_err_t handle_session_command0(session_t *cur_session,
uint32_t session_id,
SessionData *req, SessionData *resp,
const protocomm_security2_params_t *sv)
{
ESP_LOGD(TAG, "Request to handle setup0_command");
Sec2Payload *in = (Sec2Payload *) req->sec2;
if (cur_session->state != SESSION_STATE_CMD0) {
ESP_LOGW(TAG, "Invalid state of session %d (expected %d). Restarting session.",
SESSION_STATE_CMD0, cur_session->state);
sec2_new_session(cur_session, session_id);
}
if (in->sc0->client_pubkey.len != PUBLIC_KEY_LEN) {
ESP_LOGE(TAG, "Invalid public key length");
return ESP_ERR_INVALID_ARG;
}
if (in->sc0->client_username.len <= 0) {
ESP_LOGE(TAG, "Invalid username");
return ESP_ERR_INVALID_ARG;
}
cur_session->username_len = in->sc0->client_username.len;
cur_session->username = calloc(cur_session->username_len, sizeof(char));
if (!cur_session->username) {
ESP_LOGE(TAG, "Failed to allocate memory!");
return ESP_ERR_NO_MEM;
}
memcpy(cur_session->username, in->sc0->client_username.data, in->sc0->client_username.len);
ESP_LOGD(TAG, "Username: %.*s", cur_session->username_len, cur_session->username);
cur_session->client_pubkey = calloc(PUBLIC_KEY_LEN, sizeof(char));
if (!cur_session->client_pubkey ) {
ESP_LOGE(TAG, "Failed to allocate memory!");
return ESP_ERR_NO_MEM;
}
memcpy(cur_session->client_pubkey, in->sc0->client_pubkey.data, PUBLIC_KEY_LEN);
cur_session->client_pubkey_len = PUBLIC_KEY_LEN;
hexdump("Client Public Key", cur_session->client_pubkey, PUBLIC_KEY_LEN);
/* Initialize mu srp context */
cur_session->srp_hd = calloc(1, sizeof(esp_srp_handle_t));
if (!cur_session->srp_hd) {
ESP_LOGE(TAG, "Failed to allocate security context!");
return ESP_ERR_NO_MEM;
}
if (esp_srp_init(cur_session->srp_hd, ESP_NG_3072) != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialise security context!");
return ESP_FAIL;
}
char *device_pubkey = NULL;
int device_pubkey_len = 0;
cur_session->salt = (char *)sv->salt;
cur_session->salt_len = sv->salt_len;
cur_session->verifier = (char *)sv->verifier;
cur_session->verifier_len = sv->verifier_len;
ESP_LOGI(TAG, "Using salt and verifier to generate public key...");
if (sv != NULL && sv->salt != NULL && sv->salt_len != 0 && sv->verifier != NULL && sv->verifier_len != 0) {
if (esp_srp_set_salt_verifier(cur_session->srp_hd, cur_session->salt, cur_session->salt_len, cur_session->verifier, cur_session->verifier_len) != ESP_OK) {
ESP_LOGE(TAG, "Failed to set salt and verifier!");
return ESP_FAIL;
}
if (esp_srp_srv_pubkey_from_salt_verifier(cur_session->srp_hd, &device_pubkey, &device_pubkey_len) != ESP_OK) {
ESP_LOGE(TAG, "Failed to device public key!");
return ESP_FAIL;
}
}
hexdump("Device Public Key", device_pubkey, device_pubkey_len);
if (esp_srp_get_session_key(cur_session->srp_hd, cur_session->client_pubkey, cur_session->client_pubkey_len,
&cur_session->session_key, (int *)&cur_session->session_key_len) != ESP_OK) {
ESP_LOGE(TAG, "Failed to generate device session key!");
return ESP_FAIL;
}
hexdump("Session Key", cur_session->session_key, cur_session->session_key_len);
Sec2Payload *out = (Sec2Payload *) malloc(sizeof(Sec2Payload));
S2SessionResp0 *out_resp = (S2SessionResp0 *) malloc(sizeof(S2SessionResp0));
if (!out || !out_resp) {
ESP_LOGE(TAG, "Error allocating memory for response0");
free(out);
free(out_resp);
return ESP_ERR_NO_MEM;
}
sec2_payload__init(out);
s2_session_resp0__init(out_resp);
out_resp->status = STATUS__Success;
out_resp->device_pubkey.data = (uint8_t *)device_pubkey;
out_resp->device_pubkey.len = device_pubkey_len;
out_resp->device_salt.data = (uint8_t *)cur_session->salt;
out_resp->device_salt.len = cur_session->salt_len;
out->msg = SEC2_MSG_TYPE__S2Session_Response0;
out->payload_case = SEC2_PAYLOAD__PAYLOAD_SR0;
out->sr0 = out_resp;
resp->sec_ver = SEC_SCHEME_VERSION__SecScheme2;
resp->proto_case = SESSION_DATA__PROTO_SEC2;
resp->sec2 = out;
cur_session->state = SESSION_STATE_CMD1;
ESP_LOGD(TAG, "Session setup phase1 done");
return ESP_OK;
}
static esp_err_t handle_session_command1(session_t *cur_session,
uint32_t session_id,
SessionData *req, SessionData *resp)
{
ESP_LOGD(TAG, "Request to handle setup1_command");
Sec2Payload *in = (Sec2Payload *) req->sec2;
int mbed_err = -0x0001;
if (cur_session->state != SESSION_STATE_CMD1) {
ESP_LOGE(TAG, "Invalid state of session %d (expected %d)", SESSION_STATE_CMD1, cur_session->state);
return ESP_ERR_INVALID_STATE;
}
ESP_RETURN_ON_FALSE(in->sc1->client_proof.len == CLIENT_PROOF_LEN, ESP_FAIL, TAG, "The client proof length does not match");
hexdump("Client proof", (char * ) in->sc1->client_proof.data, in->sc1->client_proof.len);
char *device_proof = calloc(CLIENT_PROOF_LEN, sizeof(char));
if (!device_proof) {
ESP_LOGE(TAG, "Failed to allocate memory!");
return ESP_ERR_NO_MEM;
}
if (esp_srp_exchange_proofs(cur_session->srp_hd, cur_session->username, cur_session->username_len, (char * ) in->sc1->client_proof.data, device_proof) != ESP_OK) {
ESP_LOGE(TAG, "Failed to authenticate client proof!");
return ESP_FAIL;
}
hexdump("Device proof", device_proof, CLIENT_PROOF_LEN);
/* Initialize crypto context */
mbedtls_gcm_init(&cur_session->ctx_gcm);
/* Considering the protocomm component is only used after RF ( Wifi/Bluetooth ) is enabled.
* Hence, we can be sure that the RNG generates true random numbers */
esp_fill_random(&cur_session->iv, AES_GCM_IV_SIZE);
hexdump("Initialization vector", (char *)cur_session->iv, AES_GCM_IV_SIZE);
mbed_err = mbedtls_gcm_setkey(&cur_session->ctx_gcm, MBEDTLS_CIPHER_ID_AES, (unsigned char *)cur_session->session_key, AES_GCM_KEY_LEN);
if (mbed_err != 0) {
ESP_LOGE(TAG, "Failure at mbedtls_gcm_setkey_enc with error code : -0x%x", -mbed_err);
mbedtls_gcm_free(&cur_session->ctx_gcm);
return ESP_FAIL;
}
Sec2Payload *out = (Sec2Payload *) malloc(sizeof(Sec2Payload));
S2SessionResp1 *out_resp = (S2SessionResp1 *) malloc(sizeof(S2SessionResp1));
if (!out || !out_resp) {
ESP_LOGE(TAG, "Error allocating memory for response1");
free(out);
free(out_resp);
mbedtls_gcm_free(&cur_session->ctx_gcm);
return ESP_ERR_NO_MEM;
}
sec2_payload__init(out);
s2_session_resp1__init(out_resp);
out_resp->status = STATUS__Success;
out_resp->device_proof.data = (uint8_t *)device_proof;
out_resp->device_proof.len = CLIENT_PROOF_LEN;
out_resp->device_nonce.data = cur_session->iv;
out_resp->device_nonce.len = AES_GCM_IV_SIZE;
out->msg = SEC2_MSG_TYPE__S2Session_Response1;
out->payload_case = SEC2_PAYLOAD__PAYLOAD_SR1;
out->sr1 = out_resp;
resp->sec_ver = SEC_SCHEME_VERSION__SecScheme2;
resp->proto_case = SESSION_DATA__PROTO_SEC2;
resp->sec2 = out;
cur_session->state = SESSION_STATE_DONE;
ESP_LOGD(TAG, "Secure session established successfully");
return ESP_OK;
}
static esp_err_t sec2_session_setup(session_t *cur_session,
uint32_t session_id,
SessionData *req, SessionData *resp,
const protocomm_security2_params_t *sv)
{
Sec2Payload *in = (Sec2Payload *) req->sec2;
esp_err_t ret;
if (!in) {
ESP_LOGE(TAG, "Empty session data");
return ESP_ERR_INVALID_ARG;
}
switch (in->msg) {
case SEC2_MSG_TYPE__S2Session_Command0:
ret = handle_session_command0(cur_session, session_id, req, resp, sv);
break;
case SEC2_MSG_TYPE__S2Session_Command1:
ret = handle_session_command1(cur_session, session_id, req, resp);
break;
default:
ESP_LOGE(TAG, "Invalid security message type");
ret = ESP_ERR_INVALID_ARG;
}
return ret;
}
static void sec2_session_setup_cleanup(session_t *cur_session, uint32_t session_id, SessionData *resp)
{
Sec2Payload *out = resp->sec2;
if (!out) {
return;
}
switch (out->msg) {
case SEC2_MSG_TYPE__S2Session_Response0: {
S2SessionResp0 *out_resp0 = out->sr0;
if (out_resp0) {
free(out_resp0);
}
break;
}
case SEC2_MSG_TYPE__S2Session_Response1: {
S2SessionResp1 *out_resp1 = out->sr1;
if (out_resp1) {
free(out_resp1->device_proof.data);
free(out_resp1);
}
break;
}
default:
break;
}
free(out);
return;
}
static esp_err_t sec2_close_session(protocomm_security_handle_t handle, uint32_t session_id)
{
session_t *cur_session = (session_t *) handle;
if (!cur_session) {
return ESP_ERR_INVALID_ARG;
}
if (!cur_session || cur_session->id != session_id) {
ESP_LOGE(TAG, "Attempt to close invalid session");
return ESP_ERR_INVALID_STATE;
}
if (cur_session->state == SESSION_STATE_DONE) {
/* Free GCM context data */
mbedtls_gcm_free(&cur_session->ctx_gcm);
}
free(cur_session->username);
free(cur_session->client_pubkey);
if (cur_session->srp_hd) {
esp_srp_free(cur_session->srp_hd);
free(cur_session->srp_hd);
}
memset(cur_session, 0, sizeof(session_t));
cur_session->id = -1;
return ESP_OK;
}
static esp_err_t sec2_new_session(protocomm_security_handle_t handle, uint32_t session_id)
{
session_t *cur_session = (session_t *) handle;
if (!cur_session) {
return ESP_ERR_INVALID_ARG;
}
if (cur_session->id != -1) {
/* Only one session is allowed at a time */
ESP_LOGE(TAG, "Closing old session with id %u", cur_session->id);
sec2_close_session(cur_session, session_id);
}
cur_session->id = session_id;
return ESP_OK;
}
static esp_err_t sec2_init(protocomm_security_handle_t *handle)
{
if (!handle) {
return ESP_ERR_INVALID_ARG;
}
session_t *cur_session = (session_t *) calloc(1, sizeof(session_t));
if (!cur_session) {
ESP_LOGE(TAG, "Error allocating new session");
return ESP_ERR_NO_MEM;
}
cur_session->id = -1;
*handle = (protocomm_security_handle_t) cur_session;
return ESP_OK;
}
static esp_err_t sec2_cleanup(protocomm_security_handle_t handle)
{
session_t *cur_session = (session_t *) handle;
if (cur_session) {
sec2_close_session(handle, cur_session->id);
}
free(handle);
return ESP_OK;
}
static esp_err_t sec2_encrypt(protocomm_security_handle_t handle,
uint32_t session_id,
const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen)
{
session_t *cur_session = (session_t *) handle;
if (!cur_session) {
return ESP_ERR_INVALID_ARG;
}
if (!cur_session || cur_session->id != session_id) {
ESP_LOGE(TAG, "Session with ID %d not found", session_id);
return ESP_ERR_INVALID_STATE;
}
if (cur_session->state != SESSION_STATE_DONE) {
ESP_LOGE(TAG, "Secure session not established");
return ESP_ERR_INVALID_STATE;
}
*outlen = inlen + AES_GCM_TAG_LEN;
*outbuf = (uint8_t *) malloc(*outlen);
if (!*outbuf) {
ESP_LOGE(TAG, "Failed to allocate encrypt buf len %d", *outlen);
return ESP_ERR_NO_MEM;
}
uint8_t gcm_tag[AES_GCM_TAG_LEN];
int ret = mbedtls_gcm_crypt_and_tag(&cur_session->ctx_gcm, MBEDTLS_GCM_ENCRYPT, inlen, cur_session->iv,
AES_GCM_IV_SIZE, NULL, 0, inbuf,
*outbuf, AES_GCM_TAG_LEN, gcm_tag);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_gcm_crypt_and_tag with error code : %d", ret);
return ESP_FAIL;
}
memcpy(*outbuf + inlen, gcm_tag, AES_GCM_TAG_LEN);
return ESP_OK;
}
static esp_err_t sec2_decrypt(protocomm_security_handle_t handle,
uint32_t session_id,
const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen)
{
session_t *cur_session = (session_t *) handle;
if (!cur_session) {
return ESP_ERR_INVALID_ARG;
}
if (!cur_session || cur_session->id != session_id) {
ESP_LOGE(TAG, "Session with ID %d not found", session_id);
return ESP_ERR_INVALID_STATE;
}
if (cur_session->state != SESSION_STATE_DONE) {
ESP_LOGE(TAG, "Secure session not established");
return ESP_ERR_INVALID_STATE;
}
*outlen = inlen - AES_GCM_TAG_LEN;
*outbuf = (uint8_t *) malloc(*outlen);
if (!*outbuf) {
ESP_LOGE(TAG, "Failed to allocate decrypt buf len %d", *outlen);
return ESP_ERR_NO_MEM;
}
int ret = mbedtls_gcm_auth_decrypt(&cur_session->ctx_gcm, inlen - AES_GCM_TAG_LEN, cur_session->iv,
AES_GCM_IV_SIZE, NULL, 0, inbuf + (inlen - AES_GCM_TAG_LEN), AES_GCM_TAG_LEN, inbuf, *outbuf);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_gcm_auth_decrypt : %d", ret);
return ESP_FAIL;
}
return ESP_OK;
}
static esp_err_t sec2_req_handler(protocomm_security_handle_t handle,
const void *sec_params,
uint32_t session_id,
const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen,
void *priv_data)
{
session_t *cur_session = (session_t *) handle;
if (!cur_session) {
ESP_LOGE(TAG, "Invalid session context data");
return ESP_ERR_INVALID_ARG;
}
if (session_id != cur_session->id) {
ESP_LOGE(TAG, "Invalid session ID : %d (expected %d)", session_id, cur_session->id);
return ESP_ERR_INVALID_STATE;
}
SessionData *req;
SessionData resp;
esp_err_t ret;
req = session_data__unpack(NULL, inlen, inbuf);
if (!req) {
ESP_LOGE(TAG, "Unable to unpack setup_req");
return ESP_ERR_INVALID_ARG;
}
if (req->sec_ver != protocomm_security2.ver) {
ESP_LOGE(TAG, "Security version mismatch. Closing connection");
session_data__free_unpacked(req, NULL);
return ESP_ERR_INVALID_ARG;
}
session_data__init(&resp);
ret = sec2_session_setup(cur_session, session_id, req, &resp, (protocomm_security2_params_t *) sec_params);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Session setup error %d", ret);
session_data__free_unpacked(req, NULL);
return ESP_FAIL;
}
resp.sec_ver = req->sec_ver;
session_data__free_unpacked(req, NULL);
*outlen = session_data__get_packed_size(&resp);
*outbuf = (uint8_t *) malloc(*outlen);
if (!*outbuf) {
ESP_LOGE(TAG, "System out of memory");
return ESP_ERR_NO_MEM;
}
session_data__pack(&resp, *outbuf);
sec2_session_setup_cleanup(cur_session, session_id, &resp);
return ESP_OK;
}
const protocomm_security_t protocomm_security2 = {
.ver = 2,
.init = sec2_init,
.cleanup = sec2_cleanup,
.new_transport_session = sec2_new_session,
.close_transport_session = sec2_close_session,
.security_req_handler = sec2_req_handler,
.encrypt = sec2_encrypt,
.decrypt = sec2_decrypt,
};

View File

@@ -49,7 +49,7 @@ typedef struct {
uint32_t id;
uint8_t sec_ver;
uint8_t weak;
const protocomm_security_pop_t *pop;
const protocomm_security1_params_t *pop;
uint8_t device_pubkey[PUBLIC_KEY_LEN];
uint8_t client_pubkey[PUBLIC_KEY_LEN];
uint8_t sym_key[PUBLIC_KEY_LEN];
@@ -187,7 +187,7 @@ static esp_err_t verify_response0(session_t *session, SessionData *resp)
}
flip_endian(session->sym_key, PUBLIC_KEY_LEN);
const protocomm_security_pop_t *pop = session->pop;
const protocomm_security1_params_t *pop = session->pop;
if (pop != NULL && pop->data != NULL && pop->len != 0) {
ESP_LOGD(TAG, "Adding proof of possession");
uint8_t sha_out[PUBLIC_KEY_LEN];
@@ -638,7 +638,7 @@ esp_err_t test_req_handler (uint32_t session_id,
return ESP_OK;
}
static esp_err_t start_test_service(uint8_t sec_ver, const protocomm_security_pop_t *pop)
static esp_err_t start_test_service(uint8_t sec_ver, const protocomm_security1_params_t *pop)
{
test_pc = protocomm_new();
if (test_pc == NULL) {
@@ -686,7 +686,7 @@ static esp_err_t test_security1_no_encryption (void)
ESP_LOGI(TAG, "Starting Security 1 no encryption test");
const char *pop_data = "test pop";
protocomm_security_pop_t pop = {
protocomm_security1_params_t pop = {
.data = (const uint8_t *)pop_data,
.len = strlen(pop_data)
};
@@ -753,7 +753,7 @@ static esp_err_t test_security1_session_overflow (void)
ESP_LOGI(TAG, "Starting Security 1 session overflow test");
const char *pop_data = "test pop";
protocomm_security_pop_t pop = {
protocomm_security1_params_t pop = {
.data = (const uint8_t *)pop_data,
.len = strlen(pop_data)
};
@@ -831,7 +831,7 @@ static esp_err_t test_security1_wrong_pop (void)
ESP_LOGI(TAG, "Starting Security 1 wrong auth test");
const char *pop_data = "test pop";
protocomm_security_pop_t pop = {
protocomm_security1_params_t pop = {
.data = (const uint8_t *)pop_data,
.len = strlen(pop_data)
};
@@ -862,7 +862,7 @@ static esp_err_t test_security1_wrong_pop (void)
}
const char *wrong_pop_data = "wrong pop";
protocomm_security_pop_t wrong_pop = {
protocomm_security1_params_t wrong_pop = {
.data = (const uint8_t *)wrong_pop_data,
.len = strlen(wrong_pop_data)
};
@@ -893,7 +893,7 @@ static esp_err_t test_security1_insecure_client (void)
ESP_LOGI(TAG, "Starting Security 1 insecure client test");
const char *pop_data = "test pop";
protocomm_security_pop_t pop = {
protocomm_security1_params_t pop = {
.data = (const uint8_t *)pop_data,
.len = strlen(pop_data)
};
@@ -945,7 +945,7 @@ static esp_err_t test_security1_weak_session (void)
ESP_LOGI(TAG, "Starting Security 1 weak session test");
const char *pop_data = "test pop";
protocomm_security_pop_t pop = {
protocomm_security1_params_t pop = {
.data = (const uint8_t *)pop_data,
.len = strlen(pop_data)
};
@@ -1057,7 +1057,7 @@ static esp_err_t test_security1 (void)
ESP_LOGI(TAG, "Starting Sec1 test");
const char *pop_data = "test pop";
protocomm_security_pop_t pop = {
protocomm_security1_params_t pop = {
.data = (const uint8_t *)pop_data,
.len = strlen(pop_data)
};

View File

@@ -199,7 +199,9 @@ typedef enum wifi_prov_security {
* + proof of possession (pop) based authentication
* + AES-CTR encryption
*/
WIFI_PROV_SECURITY_1
WIFI_PROV_SECURITY_1,
WIFI_PROV_SECURITY_2
} wifi_prov_security_t;
/**
@@ -299,8 +301,8 @@ esp_err_t wifi_prov_mgr_is_provisioned(bool *provisioned);
* - ESP_FAIL : Failed to start provisioning service
* - ESP_ERR_INVALID_STATE : Provisioning manager not initialized or already started
*/
esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const char *pop,
const char *service_name, const char *service_key);
esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const char *pop, const char *salt,
const char *verifier, const char *service_name, const char *service_key);
/**
* @brief Stop provisioning service

View File

@@ -21,6 +21,7 @@
#include <protocomm.h>
#include <protocomm_security0.h>
#include <protocomm_security1.h>
#include <protocomm_security2.h>
#include "wifi_provisioning_priv.h"
@@ -93,6 +94,9 @@ struct wifi_prov_mgr_ctx {
/* Pointer to proof of possession */
protocomm_security_pop_t pop;
/* Pointer to salt and verifier */
protocomm_security_sv_t sv;
/* Handle for Provisioning Auto Stop timer */
esp_timer_handle_t autostop_timer;
@@ -307,10 +311,13 @@ static esp_err_t wifi_prov_mgr_start_service(const char *service_name, const cha
/* Set protocomm security type for endpoint */
if (prov_ctx->security == 0) {
ret = protocomm_set_security(prov_ctx->pc, "prov-session",
&protocomm_security0, NULL);
&protocomm_security0, NULL, NULL);
} else if (prov_ctx->security == 1) {
ret = protocomm_set_security(prov_ctx->pc, "prov-session",
&protocomm_security1, &prov_ctx->pop);
&protocomm_security1, &prov_ctx->pop, NULL);
} else if (prov_ctx->security == 2) {
ret = protocomm_set_security(prov_ctx->pc, "prov-session",
&protocomm_security2, NULL, &prov_ctx->sv);
} else {
ESP_LOGE(TAG, "Unsupported protocomm security version %d", prov_ctx->security);
ret = ESP_ERR_INVALID_ARG;
@@ -1330,6 +1337,7 @@ void wifi_prov_mgr_deinit(void)
if (!service_was_running && !prov_ctx) {
ESP_LOGD(TAG, "Manager already de-initialized");
RELEASE_LOCK(prov_ctx_lock);
vSemaphoreDelete(prov_ctx_lock);
return;
}
@@ -1380,10 +1388,12 @@ void wifi_prov_mgr_deinit(void)
if (esp_event_post(WIFI_PROV_EVENT, WIFI_PROV_DEINIT, NULL, 0, portMAX_DELAY) != ESP_OK) {
ESP_LOGE(TAG, "Failed to post event WIFI_PROV_DEINIT");
}
vSemaphoreDelete(prov_ctx_lock);
}
esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const char *pop,
const char *service_name, const char *service_key)
esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const char *pop, const char *salt,
const char *verifier, const char *service_name, const char *service_key)
{
uint8_t restore_wifi_flag = 0;
@@ -1459,7 +1469,8 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const
/* Initialize app data */
if (security == WIFI_PROV_SECURITY_0) {
prov_ctx->mgr_info.capabilities.no_sec = true;
} else if (pop) {
} else if (security == WIFI_PROV_SECURITY_1) {
if (pop) {
prov_ctx->pop.len = strlen(pop);
prov_ctx->pop.data = malloc(prov_ctx->pop.len);
if (!prov_ctx->pop.data) {
@@ -1471,6 +1482,25 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const
} else {
prov_ctx->mgr_info.capabilities.no_pop = true;
}
} else if (security == WIFI_PROV_SECURITY_2) {
if (salt != NULL && verifier != NULL) {
prov_ctx->sv.salt_len = 4;
prov_ctx->sv.verifier_len = 384;
prov_ctx->sv.salt = malloc(prov_ctx->sv.salt_len);
prov_ctx->sv.verifier = malloc(prov_ctx->sv.verifier_len);
if (!prov_ctx->sv.salt || !prov_ctx->sv.salt) {
ESP_LOGE(TAG, "Unable to allocate salt-verifier data");
ret = ESP_ERR_NO_MEM;
goto err;
}
memcpy((void *)prov_ctx->sv.salt, salt, prov_ctx->sv.salt_len);
memcpy((void *)prov_ctx->sv.verifier, verifier, prov_ctx->sv.verifier_len);
} else {
ESP_LOGE(TAG, "Salt and verifier cannot be NULL!");
ret = ESP_ERR_INVALID_ARG;
goto err;
}
}
prov_ctx->security = security;

View File

@@ -32,6 +32,33 @@
static const char *TAG = "app";
const char sec2_salt[4] = {0xc1, 0x85, 0x74, 0xfe};
const char sec2_verifier[384] = {0x88, 0x98, 0x2a, 0xd3, 0xb1, 0x8a, 0xf6, 0xe3, 0x00, 0x5d, 0x34, 0x63, 0x56, 0x73, 0x2a, 0x03,
0x7b, 0x1c, 0xae, 0xe8, 0x2e, 0x59, 0x03, 0x48, 0x68, 0x00, 0xba, 0xa1, 0xb0, 0xff, 0x12, 0xca,
0xa7, 0xc9, 0xff, 0x69, 0xaf, 0x7a, 0x1e, 0x53, 0x98, 0x15, 0x79, 0xd1, 0x11, 0x83, 0x68, 0xf2,
0x8c, 0x7a, 0xcf, 0x8b, 0x1b, 0x25, 0x2e, 0x0c, 0xcb, 0xdc, 0x6a, 0x7c, 0xda, 0x2e, 0x6d, 0x5b,
0xcc, 0xaa, 0x8c, 0x6e, 0x92, 0x07, 0xd8, 0x48, 0x08, 0xd1, 0xbb, 0x72, 0x80, 0x65, 0xfd, 0x7d,
0x77, 0xfb, 0x76, 0x14, 0x62, 0x58, 0xdd, 0xc4, 0xbf, 0x6b, 0xe4, 0x48, 0x83, 0xc4, 0x0b, 0x83,
0x16, 0xa7, 0xf5, 0x1c, 0xd5, 0x9a, 0x47, 0xbc, 0xb3, 0xcd, 0x7c, 0x15, 0x5c, 0x6d, 0x40, 0x6e,
0xaf, 0xa6, 0x7c, 0x49, 0x12, 0x07, 0x74, 0xa3, 0xf3, 0x98, 0x8d, 0x12, 0x69, 0xbd, 0xbc, 0x29,
0xe8, 0x2b, 0x03, 0x82, 0x50, 0x5e, 0xb2, 0x95, 0xbd, 0x7d, 0x36, 0x43, 0x20, 0xd1, 0x0f, 0xbc,
0x0e, 0xd5, 0x92, 0xe4, 0xe2, 0x64, 0xe6, 0x90, 0x66, 0xf5, 0x27, 0xee, 0x7e, 0xf1, 0x02, 0x35,
0x8c, 0xea, 0xe7, 0x96, 0x0b, 0x00, 0x57, 0x54, 0xfa, 0x9e, 0x08, 0x75, 0xb9, 0x36, 0x71, 0x5e,
0x68, 0xb8, 0x66, 0xff, 0x0c, 0x1b, 0x2e, 0xbe, 0x23, 0x8b, 0x37, 0xc1, 0xd5, 0x3b, 0xf7, 0x7f,
0xcf, 0xb7, 0x65, 0x09, 0xda, 0x2b, 0x01, 0xbb, 0xd0, 0x5e, 0xf6, 0xd3, 0x21, 0xae, 0x33, 0x3d,
0xb7, 0xdf, 0xfb, 0xb6, 0x88, 0xbe, 0x9e, 0xb5, 0xef, 0xd8, 0x74, 0x58, 0x08, 0xef, 0x8a, 0x40,
0xa2, 0xda, 0x63, 0xe1, 0xb9, 0x71, 0x21, 0x46, 0xae, 0x45, 0x1f, 0x76, 0x14, 0xbf, 0x74, 0xb6,
0x2e, 0xe2, 0x81, 0x7e, 0x5e, 0x99, 0x15, 0x2a, 0xd7, 0x73, 0xbf, 0x0a, 0x00, 0xe8, 0xea, 0x3c,
0xbe, 0xb7, 0x70, 0xb3, 0x63, 0xa2, 0x5c, 0xff, 0x37, 0xbd, 0x40, 0x9a, 0xa9, 0x6c, 0xde, 0x1e,
0xc0, 0x73, 0xd3, 0x00, 0x00, 0x89, 0x78, 0x16, 0x3b, 0x86, 0x36, 0x99, 0x36, 0xa9, 0x7c, 0x92,
0xa2, 0xea, 0x92, 0x37, 0x1f, 0x13, 0xd4, 0x1a, 0x88, 0x3d, 0x2b, 0x49, 0xb1, 0x27, 0xb6, 0x8c,
0xa5, 0x54, 0xf7, 0xba, 0x1b, 0x3e, 0x13, 0xe4, 0x52, 0xfc, 0xa2, 0x92, 0xa1, 0x77, 0x21, 0x02,
0x16, 0xd9, 0xd1, 0x52, 0xb5, 0x2a, 0x6a, 0xc7, 0xe6, 0x2d, 0x1c, 0x26, 0x33, 0x89, 0x28, 0x36,
0xeb, 0xcb, 0x4b, 0x19, 0x77, 0x6a, 0xe7, 0x2e, 0x1a, 0x53, 0x3e, 0xe1, 0xf4, 0x12, 0x94, 0x2a,
0x90, 0xca, 0x47, 0x65, 0xdc, 0xca, 0xc5, 0x5c, 0xb3, 0xea, 0x70, 0xf9, 0xf0, 0xe1, 0x17, 0xc3,
0xfb, 0x9d, 0xbd, 0xf6, 0x27, 0x3d, 0xa9, 0xd0, 0x4c, 0xb7, 0x6f, 0xe6, 0x21, 0x25, 0x0f, 0x29};
/* Signal Wi-Fi events on this event-group */
const int WIFI_CONNECTED_EVENT = BIT0;
static EventGroupHandle_t wifi_event_group;
@@ -254,7 +281,8 @@ void app_main(void)
* using X25519 key exchange and proof of possession (pop) and AES-CTR
* for encryption/decryption of messages.
*/
wifi_prov_security_t security = WIFI_PROV_SECURITY_1;
// wifi_prov_security_t security = WIFI_PROV_SECURITY_1;
wifi_prov_security_t security = WIFI_PROV_SECURITY_2;
/* Do we want a proof-of-possession (ignored if Security 0 is selected):
* - this should be a string with length > 0
@@ -300,7 +328,8 @@ void app_main(void)
*/
wifi_prov_mgr_endpoint_create("custom-data");
/* Start provisioning service */
ESP_ERROR_CHECK(wifi_prov_mgr_start_provisioning(security, pop, service_name, service_key));
// ESP_ERROR_CHECK(wifi_prov_mgr_start_provisioning(security, pop, NULL, NULL, service_name, service_key));
ESP_ERROR_CHECK(wifi_prov_mgr_start_provisioning(security, NULL, sec2_salt, sec2_verifier, service_name, service_key));
/* The handler for the optional endpoint created above.
* This call must be made after starting the provisioning, and only if the endpoint

View File

@@ -9,3 +9,7 @@ CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_EXAMPLE_RESET_PROVISIONED=y
CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION=n
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y

View File

@@ -1072,8 +1072,6 @@ components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp
components/openthread/include/esp_openthread.h
components/openthread/include/esp_openthread_lock.h
components/openthread/include/esp_openthread_netif_glue.h
components/protocomm/include/common/protocomm.h
components/protocomm/include/security/protocomm_security.h
components/protocomm/include/security/protocomm_security0.h
components/protocomm/include/security/protocomm_security1.h
components/protocomm/include/transports/protocomm_console.h
@@ -1093,8 +1091,6 @@ components/protocomm/python/sec0_pb2.py
components/protocomm/python/sec1_pb2.py
components/protocomm/python/sec2_pb2.py
components/protocomm/python/session_pb2.py
components/protocomm/src/common/protocomm_priv.h
components/protocomm/src/security/security0.c
components/pthread/pthread_cond_var.c
components/pthread/pthread_internal.h
components/pthread/pthread_local_storage.c