forked from espressif/esp-idf
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:
@@ -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();
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
*
|
||||
|
@@ -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
|
||||
|
26
components/protocomm/include/security/protocomm_security2.h
Normal file
26
components/protocomm/include/security/protocomm_security2.h
Normal 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
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
546
components/protocomm/src/crypto/srp6a/esp_srp.c
Normal file
546
components/protocomm/src/crypto/srp6a/esp_srp.c
Normal 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;
|
||||
}
|
148
components/protocomm/src/crypto/srp6a/esp_srp_mpi.c
Normal file
148
components/protocomm/src/crypto/srp6a/esp_srp_mpi.c
Normal 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;
|
||||
}
|
103
components/protocomm/src/crypto/srp6a/include/esp_srp.h
Normal file
103
components/protocomm/src/crypto/srp6a/include/esp_srp.h
Normal 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
|
52
components/protocomm/src/crypto/srp6a/include/esp_srp_mpi.h
Normal file
52
components/protocomm/src/crypto/srp6a/include/esp_srp_mpi.h
Normal 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
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
539
components/protocomm/src/security/security2.c
Normal file
539
components/protocomm/src/security/security2.c
Normal 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,
|
||||
};
|
@@ -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)
|
||||
};
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user