Merge branch 'feature/protocomm_security_version_2' into 'master'

Protocomm: Add SRP6a-based security scheme

Closes IDF-3014

See merge request espressif/esp-idf!18183
pull/7436/merge
Aditya Patwardhan 2022-06-18 00:04:40 +08:00
commit c2ccc383da
50 zmienionych plików z 3698 dodań i 329 usunięć

Wyświetl plik

@ -155,6 +155,7 @@ exclude =
components/protocomm/python/constants_pb2.py,
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/wifi_provisioning/python/wifi_scan_pb2.py,
components/wifi_provisioning/python/wifi_config_pb2.py,

Wyświetl plik

@ -1,16 +1,8 @@
// Copyright 2019 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: 2019-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
@ -234,9 +226,13 @@ typedef union {
typedef enum esp_local_ctrl_proto_sec {
PROTOCOM_SEC0 = 0,
PROTOCOM_SEC1,
PROTOCOM_SEC2,
PROTOCOM_SEC_CUSTOM,
} esp_local_ctrl_proto_sec_t;
typedef protocomm_security1_params_t esp_local_ctrl_security1_params_t;
typedef protocomm_security2_params_t esp_local_ctrl_security2_params_t;
/**
* Protocom security configs
*/
@ -253,10 +249,22 @@ typedef struct esp_local_ctrl_proto_sec_cfg {
*/
void *custom_handle;
/**
* Proof of possession to be used for local control. Could be NULL.
*/
void *pop;
/* Anonymous union */
union {
/**
* Proof of possession to be used for local control. Could be NULL.
*/
const void *pop __attribute__((deprecated("use sec_params field instead")));
/**
* Pointer to security params (NULL if not needed).
* This is not needed for protocomm security 0
* This pointer should hold the struct of type
* esp_local_ctrl_security1_params_t for protocomm security 1
* and esp_local_ctrl_security2_params_t for protocomm security 2 respectively. Could be NULL.
*/
const void *sec_params;
};
} esp_local_ctrl_proto_sec_cfg_t;
/**

Wyświetl plik

@ -1,16 +1,8 @@
// Copyright 2019 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: 2019-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
@ -20,6 +12,7 @@
#include <protocomm.h>
#include <protocomm_security0.h>
#include <protocomm_security1.h>
#include <protocomm_security2.h>
#include <esp_local_ctrl.h>
#include "esp_local_ctrl_priv.h"
@ -150,21 +143,39 @@ esp_err_t esp_local_ctrl_start(const esp_local_ctrl_config_t *config)
return ret;
}
protocomm_security_t *proto_sec_handle;
protocomm_security_t *proto_sec_handle = NULL;
switch (local_ctrl_inst_ctx->config.proto_sec.version) {
case PROTOCOM_SEC_CUSTOM:
proto_sec_handle = local_ctrl_inst_ctx->config.proto_sec.custom_handle;
break;
case PROTOCOM_SEC1:
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1
proto_sec_handle = (protocomm_security_t *) &protocomm_security1;
#else
// Enable SECURITY_VERSION_1 in Protocomm configuration menu
return ESP_ERR_NOT_SUPPORTED;
#endif
break;
case PROTOCOM_SEC2:
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2
proto_sec_handle = (protocomm_security_t *) &protocomm_security2;
break;
#else
// Enable SECURITY_VERSION_2 in Protocomm configuration menu
return ESP_ERR_NOT_SUPPORTED;
#endif
case PROTOCOM_SEC0:
default:
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0
proto_sec_handle = (protocomm_security_t *) &protocomm_security0;
#else
// Enable SECURITY_VERSION_0 in Protocomm configuration menu
return ESP_ERR_NOT_SUPPORTED;
#endif
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.sec_params);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set session endpoint");
esp_local_ctrl_stop();

Wyświetl plik

@ -1,18 +1,34 @@
set(include_dirs include/common
include/security
include/transports)
set(priv_include_dirs proto-c src/common)
include/security
include/transports)
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"
"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")
if(CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0)
list(APPEND srcs
"src/security/security0.c")
endif()
if(CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1)
list(APPEND srcs
"src/security/security1.c")
endif()
if(CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2)
list(APPEND srcs
"src/security/security2.c"
"src/crypto/srp6a/esp_srp.c"
"src/crypto/srp6a/esp_srp_mpi.c")
endif()
if(CONFIG_BT_ENABLED)
if(CONFIG_BT_BLUEDROID_ENABLED)
list(APPEND srcs

Wyświetl plik

@ -0,0 +1,29 @@
menu "Protocomm"
config ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0
bool "Support protocomm security version 0 (no security)"
default y
help
Enable support of security version 0.
Disabling this option saves some code size.
Consult the Enabling protocomm security version section of the
Protocomm documentation in ESP-IDF Programming guide for more details.
config ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1
bool "Support protocomm security version 1 (Curve25519 key exchange + AES-CTR encryption/decryption)"
default y
help
Enable support of security version 1.
Disabling this option saves some code size.
Consult the Enabling protocomm security version section of the
Protocomm documentation in ESP-IDF Programming guide for more details.
config ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2
bool "Support protocomm security version 2 (SRP6a-based key exchange + AES-GCM encryption/decryption)"
default n
help
Enable support of security version 2.
Disabling this option saves some code size.
Consult the Enabling protocomm security version section of the
Protocomm documentation in ESP-IDF Programming guide for more details.
endmenu

Wyświetl plik

@ -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.
*
* @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
* 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] 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
*

Wyświetl plik

@ -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

Wyświetl plik

@ -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
@ -20,6 +12,7 @@
extern "C" {
#endif
#if CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0
/**
* @brief Protocomm security version 0 implementation
*
@ -27,6 +20,7 @@ extern "C" {
* security is required for the protocomm instance
*/
extern const protocomm_security_t protocomm_security0;
#endif
#ifdef __cplusplus
}

Wyświetl plik

@ -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
@ -20,6 +12,7 @@
extern "C" {
#endif
#if CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1
/**
* @brief Protocomm security version 1 implementation
*
@ -27,6 +20,7 @@ extern "C" {
* Curve25519 key exchange and AES-256-CTR encryption
*/
extern const protocomm_security_t protocomm_security1;
#endif
#ifdef __cplusplus
}

Wyświetl plik

@ -0,0 +1,28 @@
/*
* 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
#if CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2
/**
* @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;
#endif
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -0,0 +1,574 @@
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: sec2.proto */
/* Do not generate deprecated warnings for self */
#ifndef PROTOBUF_C__NO_DEPRECATED
#define PROTOBUF_C__NO_DEPRECATED
#endif
#include "sec2.pb-c.h"
void s2_session_cmd0__init
(S2SessionCmd0 *message)
{
static const S2SessionCmd0 init_value = S2_SESSION_CMD0__INIT;
*message = init_value;
}
size_t s2_session_cmd0__get_packed_size
(const S2SessionCmd0 *message)
{
assert(message->base.descriptor == &s2_session_cmd0__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t s2_session_cmd0__pack
(const S2SessionCmd0 *message,
uint8_t *out)
{
assert(message->base.descriptor == &s2_session_cmd0__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t s2_session_cmd0__pack_to_buffer
(const S2SessionCmd0 *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &s2_session_cmd0__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
S2SessionCmd0 *
s2_session_cmd0__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (S2SessionCmd0 *)
protobuf_c_message_unpack (&s2_session_cmd0__descriptor,
allocator, len, data);
}
void s2_session_cmd0__free_unpacked
(S2SessionCmd0 *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &s2_session_cmd0__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void s2_session_resp0__init
(S2SessionResp0 *message)
{
static const S2SessionResp0 init_value = S2_SESSION_RESP0__INIT;
*message = init_value;
}
size_t s2_session_resp0__get_packed_size
(const S2SessionResp0 *message)
{
assert(message->base.descriptor == &s2_session_resp0__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t s2_session_resp0__pack
(const S2SessionResp0 *message,
uint8_t *out)
{
assert(message->base.descriptor == &s2_session_resp0__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t s2_session_resp0__pack_to_buffer
(const S2SessionResp0 *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &s2_session_resp0__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
S2SessionResp0 *
s2_session_resp0__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (S2SessionResp0 *)
protobuf_c_message_unpack (&s2_session_resp0__descriptor,
allocator, len, data);
}
void s2_session_resp0__free_unpacked
(S2SessionResp0 *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &s2_session_resp0__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void s2_session_cmd1__init
(S2SessionCmd1 *message)
{
static const S2SessionCmd1 init_value = S2_SESSION_CMD1__INIT;
*message = init_value;
}
size_t s2_session_cmd1__get_packed_size
(const S2SessionCmd1 *message)
{
assert(message->base.descriptor == &s2_session_cmd1__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t s2_session_cmd1__pack
(const S2SessionCmd1 *message,
uint8_t *out)
{
assert(message->base.descriptor == &s2_session_cmd1__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t s2_session_cmd1__pack_to_buffer
(const S2SessionCmd1 *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &s2_session_cmd1__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
S2SessionCmd1 *
s2_session_cmd1__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (S2SessionCmd1 *)
protobuf_c_message_unpack (&s2_session_cmd1__descriptor,
allocator, len, data);
}
void s2_session_cmd1__free_unpacked
(S2SessionCmd1 *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &s2_session_cmd1__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void s2_session_resp1__init
(S2SessionResp1 *message)
{
static const S2SessionResp1 init_value = S2_SESSION_RESP1__INIT;
*message = init_value;
}
size_t s2_session_resp1__get_packed_size
(const S2SessionResp1 *message)
{
assert(message->base.descriptor == &s2_session_resp1__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t s2_session_resp1__pack
(const S2SessionResp1 *message,
uint8_t *out)
{
assert(message->base.descriptor == &s2_session_resp1__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t s2_session_resp1__pack_to_buffer
(const S2SessionResp1 *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &s2_session_resp1__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
S2SessionResp1 *
s2_session_resp1__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (S2SessionResp1 *)
protobuf_c_message_unpack (&s2_session_resp1__descriptor,
allocator, len, data);
}
void s2_session_resp1__free_unpacked
(S2SessionResp1 *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &s2_session_resp1__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void sec2_payload__init
(Sec2Payload *message)
{
static const Sec2Payload init_value = SEC2_PAYLOAD__INIT;
*message = init_value;
}
size_t sec2_payload__get_packed_size
(const Sec2Payload *message)
{
assert(message->base.descriptor == &sec2_payload__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t sec2_payload__pack
(const Sec2Payload *message,
uint8_t *out)
{
assert(message->base.descriptor == &sec2_payload__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t sec2_payload__pack_to_buffer
(const Sec2Payload *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &sec2_payload__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
Sec2Payload *
sec2_payload__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (Sec2Payload *)
protobuf_c_message_unpack (&sec2_payload__descriptor,
allocator, len, data);
}
void sec2_payload__free_unpacked
(Sec2Payload *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &sec2_payload__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
static const ProtobufCFieldDescriptor s2_session_cmd0__field_descriptors[2] =
{
{
"client_username",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
offsetof(S2SessionCmd0, client_username),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"client_pubkey",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
offsetof(S2SessionCmd0, client_pubkey),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned s2_session_cmd0__field_indices_by_name[] = {
1, /* field[1] = client_pubkey */
0, /* field[0] = client_username */
};
static const ProtobufCIntRange s2_session_cmd0__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 2 }
};
const ProtobufCMessageDescriptor s2_session_cmd0__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"S2SessionCmd0",
"S2SessionCmd0",
"S2SessionCmd0",
"",
sizeof(S2SessionCmd0),
2,
s2_session_cmd0__field_descriptors,
s2_session_cmd0__field_indices_by_name,
1, s2_session_cmd0__number_ranges,
(ProtobufCMessageInit) s2_session_cmd0__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor s2_session_resp0__field_descriptors[3] =
{
{
"status",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_ENUM,
0, /* quantifier_offset */
offsetof(S2SessionResp0, status),
&status__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"device_pubkey",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
offsetof(S2SessionResp0, device_pubkey),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"device_salt",
3,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
offsetof(S2SessionResp0, device_salt),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned s2_session_resp0__field_indices_by_name[] = {
1, /* field[1] = device_pubkey */
2, /* field[2] = device_salt */
0, /* field[0] = status */
};
static const ProtobufCIntRange s2_session_resp0__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 3 }
};
const ProtobufCMessageDescriptor s2_session_resp0__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"S2SessionResp0",
"S2SessionResp0",
"S2SessionResp0",
"",
sizeof(S2SessionResp0),
3,
s2_session_resp0__field_descriptors,
s2_session_resp0__field_indices_by_name,
1, s2_session_resp0__number_ranges,
(ProtobufCMessageInit) s2_session_resp0__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor s2_session_cmd1__field_descriptors[1] =
{
{
"client_proof",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
offsetof(S2SessionCmd1, client_proof),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned s2_session_cmd1__field_indices_by_name[] = {
0, /* field[0] = client_proof */
};
static const ProtobufCIntRange s2_session_cmd1__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 1 }
};
const ProtobufCMessageDescriptor s2_session_cmd1__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"S2SessionCmd1",
"S2SessionCmd1",
"S2SessionCmd1",
"",
sizeof(S2SessionCmd1),
1,
s2_session_cmd1__field_descriptors,
s2_session_cmd1__field_indices_by_name,
1, s2_session_cmd1__number_ranges,
(ProtobufCMessageInit) s2_session_cmd1__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor s2_session_resp1__field_descriptors[3] =
{
{
"status",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_ENUM,
0, /* quantifier_offset */
offsetof(S2SessionResp1, status),
&status__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"device_proof",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
offsetof(S2SessionResp1, device_proof),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"device_nonce",
3,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
offsetof(S2SessionResp1, device_nonce),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned s2_session_resp1__field_indices_by_name[] = {
2, /* field[2] = device_nonce */
1, /* field[1] = device_proof */
0, /* field[0] = status */
};
static const ProtobufCIntRange s2_session_resp1__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 3 }
};
const ProtobufCMessageDescriptor s2_session_resp1__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"S2SessionResp1",
"S2SessionResp1",
"S2SessionResp1",
"",
sizeof(S2SessionResp1),
3,
s2_session_resp1__field_descriptors,
s2_session_resp1__field_indices_by_name,
1, s2_session_resp1__number_ranges,
(ProtobufCMessageInit) s2_session_resp1__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor sec2_payload__field_descriptors[5] =
{
{
"msg",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_ENUM,
0, /* quantifier_offset */
offsetof(Sec2Payload, msg),
&sec2_msg_type__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"sc0",
20,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(Sec2Payload, payload_case),
offsetof(Sec2Payload, sc0),
&s2_session_cmd0__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"sr0",
21,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(Sec2Payload, payload_case),
offsetof(Sec2Payload, sr0),
&s2_session_resp0__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"sc1",
22,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(Sec2Payload, payload_case),
offsetof(Sec2Payload, sc1),
&s2_session_cmd1__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"sr1",
23,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(Sec2Payload, payload_case),
offsetof(Sec2Payload, sr1),
&s2_session_resp1__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned sec2_payload__field_indices_by_name[] = {
0, /* field[0] = msg */
1, /* field[1] = sc0 */
3, /* field[3] = sc1 */
2, /* field[2] = sr0 */
4, /* field[4] = sr1 */
};
static const ProtobufCIntRange sec2_payload__number_ranges[2 + 1] =
{
{ 1, 0 },
{ 20, 1 },
{ 0, 5 }
};
const ProtobufCMessageDescriptor sec2_payload__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"Sec2Payload",
"Sec2Payload",
"Sec2Payload",
"",
sizeof(Sec2Payload),
5,
sec2_payload__field_descriptors,
sec2_payload__field_indices_by_name,
2, sec2_payload__number_ranges,
(ProtobufCMessageInit) sec2_payload__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCEnumValue sec2_msg_type__enum_values_by_number[4] =
{
{ "S2Session_Command0", "SEC2_MSG_TYPE__S2Session_Command0", 0 },
{ "S2Session_Response0", "SEC2_MSG_TYPE__S2Session_Response0", 1 },
{ "S2Session_Command1", "SEC2_MSG_TYPE__S2Session_Command1", 2 },
{ "S2Session_Response1", "SEC2_MSG_TYPE__S2Session_Response1", 3 },
};
static const ProtobufCIntRange sec2_msg_type__value_ranges[] = {
{0, 0},{0, 4}
};
static const ProtobufCEnumValueIndex sec2_msg_type__enum_values_by_name[4] =
{
{ "S2Session_Command0", 0 },
{ "S2Session_Command1", 2 },
{ "S2Session_Response0", 1 },
{ "S2Session_Response1", 3 },
};
const ProtobufCEnumDescriptor sec2_msg_type__descriptor =
{
PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
"Sec2MsgType",
"Sec2MsgType",
"Sec2MsgType",
"",
4,
sec2_msg_type__enum_values_by_number,
4,
sec2_msg_type__enum_values_by_name,
1,
sec2_msg_type__value_ranges,
NULL,NULL,NULL,NULL /* reserved[1234] */
};

Wyświetl plik

@ -0,0 +1,270 @@
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: sec2.proto */
#ifndef PROTOBUF_C_sec2_2eproto__INCLUDED
#define PROTOBUF_C_sec2_2eproto__INCLUDED
#include <protobuf-c/protobuf-c.h>
PROTOBUF_C__BEGIN_DECLS
#if PROTOBUF_C_VERSION_NUMBER < 1003000
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
#elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
#endif
#include "constants.pb-c.h"
typedef struct S2SessionCmd0 S2SessionCmd0;
typedef struct S2SessionResp0 S2SessionResp0;
typedef struct S2SessionCmd1 S2SessionCmd1;
typedef struct S2SessionResp1 S2SessionResp1;
typedef struct Sec2Payload Sec2Payload;
/* --- enums --- */
/*
* A message must be of type Cmd0 / Cmd1 / Resp0 / Resp1
*/
typedef enum _Sec2MsgType {
SEC2_MSG_TYPE__S2Session_Command0 = 0,
SEC2_MSG_TYPE__S2Session_Response0 = 1,
SEC2_MSG_TYPE__S2Session_Command1 = 2,
SEC2_MSG_TYPE__S2Session_Response1 = 3
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(SEC2_MSG_TYPE)
} Sec2MsgType;
/* --- messages --- */
/*
* Data structure of Session command0 packet
*/
struct S2SessionCmd0
{
ProtobufCMessage base;
ProtobufCBinaryData client_username;
ProtobufCBinaryData client_pubkey;
};
#define S2_SESSION_CMD0__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&s2_session_cmd0__descriptor) \
, {0,NULL}, {0,NULL} }
/*
* Data structure of Session response0 packet
*/
struct S2SessionResp0
{
ProtobufCMessage base;
Status status;
ProtobufCBinaryData device_pubkey;
ProtobufCBinaryData device_salt;
};
#define S2_SESSION_RESP0__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&s2_session_resp0__descriptor) \
, STATUS__Success, {0,NULL}, {0,NULL} }
/*
* Data structure of Session command1 packet
*/
struct S2SessionCmd1
{
ProtobufCMessage base;
ProtobufCBinaryData client_proof;
};
#define S2_SESSION_CMD1__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&s2_session_cmd1__descriptor) \
, {0,NULL} }
/*
* Data structure of Session response1 packet
*/
struct S2SessionResp1
{
ProtobufCMessage base;
Status status;
ProtobufCBinaryData device_proof;
ProtobufCBinaryData device_nonce;
};
#define S2_SESSION_RESP1__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&s2_session_resp1__descriptor) \
, STATUS__Success, {0,NULL}, {0,NULL} }
typedef enum {
SEC2_PAYLOAD__PAYLOAD__NOT_SET = 0,
SEC2_PAYLOAD__PAYLOAD_SC0 = 20,
SEC2_PAYLOAD__PAYLOAD_SR0 = 21,
SEC2_PAYLOAD__PAYLOAD_SC1 = 22,
SEC2_PAYLOAD__PAYLOAD_SR1 = 23
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(SEC2_PAYLOAD__PAYLOAD__CASE)
} Sec2Payload__PayloadCase;
/*
* Payload structure of session data
*/
struct Sec2Payload
{
ProtobufCMessage base;
/*
*!< Type of message
*/
Sec2MsgType msg;
Sec2Payload__PayloadCase payload_case;
union {
/*
*!< Payload data interpreted as Cmd0
*/
S2SessionCmd0 *sc0;
/*
*!< Payload data interpreted as Resp0
*/
S2SessionResp0 *sr0;
/*
*!< Payload data interpreted as Cmd1
*/
S2SessionCmd1 *sc1;
/*
*!< Payload data interpreted as Resp1
*/
S2SessionResp1 *sr1;
};
};
#define SEC2_PAYLOAD__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&sec2_payload__descriptor) \
, SEC2_MSG_TYPE__S2Session_Command0, SEC2_PAYLOAD__PAYLOAD__NOT_SET, {0} }
/* S2SessionCmd0 methods */
void s2_session_cmd0__init
(S2SessionCmd0 *message);
size_t s2_session_cmd0__get_packed_size
(const S2SessionCmd0 *message);
size_t s2_session_cmd0__pack
(const S2SessionCmd0 *message,
uint8_t *out);
size_t s2_session_cmd0__pack_to_buffer
(const S2SessionCmd0 *message,
ProtobufCBuffer *buffer);
S2SessionCmd0 *
s2_session_cmd0__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void s2_session_cmd0__free_unpacked
(S2SessionCmd0 *message,
ProtobufCAllocator *allocator);
/* S2SessionResp0 methods */
void s2_session_resp0__init
(S2SessionResp0 *message);
size_t s2_session_resp0__get_packed_size
(const S2SessionResp0 *message);
size_t s2_session_resp0__pack
(const S2SessionResp0 *message,
uint8_t *out);
size_t s2_session_resp0__pack_to_buffer
(const S2SessionResp0 *message,
ProtobufCBuffer *buffer);
S2SessionResp0 *
s2_session_resp0__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void s2_session_resp0__free_unpacked
(S2SessionResp0 *message,
ProtobufCAllocator *allocator);
/* S2SessionCmd1 methods */
void s2_session_cmd1__init
(S2SessionCmd1 *message);
size_t s2_session_cmd1__get_packed_size
(const S2SessionCmd1 *message);
size_t s2_session_cmd1__pack
(const S2SessionCmd1 *message,
uint8_t *out);
size_t s2_session_cmd1__pack_to_buffer
(const S2SessionCmd1 *message,
ProtobufCBuffer *buffer);
S2SessionCmd1 *
s2_session_cmd1__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void s2_session_cmd1__free_unpacked
(S2SessionCmd1 *message,
ProtobufCAllocator *allocator);
/* S2SessionResp1 methods */
void s2_session_resp1__init
(S2SessionResp1 *message);
size_t s2_session_resp1__get_packed_size
(const S2SessionResp1 *message);
size_t s2_session_resp1__pack
(const S2SessionResp1 *message,
uint8_t *out);
size_t s2_session_resp1__pack_to_buffer
(const S2SessionResp1 *message,
ProtobufCBuffer *buffer);
S2SessionResp1 *
s2_session_resp1__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void s2_session_resp1__free_unpacked
(S2SessionResp1 *message,
ProtobufCAllocator *allocator);
/* Sec2Payload methods */
void sec2_payload__init
(Sec2Payload *message);
size_t sec2_payload__get_packed_size
(const Sec2Payload *message);
size_t sec2_payload__pack
(const Sec2Payload *message,
uint8_t *out);
size_t sec2_payload__pack_to_buffer
(const Sec2Payload *message,
ProtobufCBuffer *buffer);
Sec2Payload *
sec2_payload__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void sec2_payload__free_unpacked
(Sec2Payload *message,
ProtobufCAllocator *allocator);
/* --- per-message closures --- */
typedef void (*S2SessionCmd0_Closure)
(const S2SessionCmd0 *message,
void *closure_data);
typedef void (*S2SessionResp0_Closure)
(const S2SessionResp0 *message,
void *closure_data);
typedef void (*S2SessionCmd1_Closure)
(const S2SessionCmd1 *message,
void *closure_data);
typedef void (*S2SessionResp1_Closure)
(const S2SessionResp1 *message,
void *closure_data);
typedef void (*Sec2Payload_Closure)
(const Sec2Payload *message,
void *closure_data);
/* --- services --- */
/* --- descriptors --- */
extern const ProtobufCEnumDescriptor sec2_msg_type__descriptor;
extern const ProtobufCMessageDescriptor s2_session_cmd0__descriptor;
extern const ProtobufCMessageDescriptor s2_session_resp0__descriptor;
extern const ProtobufCMessageDescriptor s2_session_cmd1__descriptor;
extern const ProtobufCMessageDescriptor s2_session_resp1__descriptor;
extern const ProtobufCMessageDescriptor sec2_payload__descriptor;
PROTOBUF_C__END_DECLS
#endif /* PROTOBUF_C_sec2_2eproto__INCLUDED */

Wyświetl plik

@ -52,7 +52,7 @@ void session_data__free_unpacked
assert(message->base.descriptor == &session_data__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
static const ProtobufCFieldDescriptor session_data__field_descriptors[3] =
static const ProtobufCFieldDescriptor session_data__field_descriptors[4] =
{
{
"sec_ver",
@ -90,17 +90,30 @@ static const ProtobufCFieldDescriptor session_data__field_descriptors[3] =
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"sec2",
12,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(SessionData, proto_case),
offsetof(SessionData, sec2),
&sec2_payload__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned session_data__field_indices_by_name[] = {
1, /* field[1] = sec0 */
2, /* field[2] = sec1 */
3, /* field[3] = sec2 */
0, /* field[0] = sec_ver */
};
static const ProtobufCIntRange session_data__number_ranges[2 + 1] =
{
{ 2, 0 },
{ 10, 1 },
{ 0, 3 }
{ 0, 4 }
};
const ProtobufCMessageDescriptor session_data__descriptor =
{
@ -110,25 +123,27 @@ const ProtobufCMessageDescriptor session_data__descriptor =
"SessionData",
"",
sizeof(SessionData),
3,
4,
session_data__field_descriptors,
session_data__field_indices_by_name,
2, session_data__number_ranges,
(ProtobufCMessageInit) session_data__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCEnumValue sec_scheme_version__enum_values_by_number[2] =
static const ProtobufCEnumValue sec_scheme_version__enum_values_by_number[3] =
{
{ "SecScheme0", "SEC_SCHEME_VERSION__SecScheme0", 0 },
{ "SecScheme1", "SEC_SCHEME_VERSION__SecScheme1", 1 },
{ "SecScheme2", "SEC_SCHEME_VERSION__SecScheme2", 2 },
};
static const ProtobufCIntRange sec_scheme_version__value_ranges[] = {
{0, 0},{0, 2}
{0, 0},{0, 3}
};
static const ProtobufCEnumValueIndex sec_scheme_version__enum_values_by_name[2] =
static const ProtobufCEnumValueIndex sec_scheme_version__enum_values_by_name[3] =
{
{ "SecScheme0", 0 },
{ "SecScheme1", 1 },
{ "SecScheme2", 2 },
};
const ProtobufCEnumDescriptor sec_scheme_version__descriptor =
{
@ -137,9 +152,9 @@ const ProtobufCEnumDescriptor sec_scheme_version__descriptor =
"SecSchemeVersion",
"SecSchemeVersion",
"",
2,
3,
sec_scheme_version__enum_values_by_number,
2,
3,
sec_scheme_version__enum_values_by_name,
1,
sec_scheme_version__value_ranges,

Wyświetl plik

@ -16,6 +16,7 @@ PROTOBUF_C__BEGIN_DECLS
#include "sec0.pb-c.h"
#include "sec1.pb-c.h"
#include "sec2.pb-c.h"
typedef struct SessionData SessionData;
@ -34,7 +35,11 @@ typedef enum _SecSchemeVersion {
/*
*!< Security scheme 1 - Curve25519 + AES-256-CTR
*/
SEC_SCHEME_VERSION__SecScheme1 = 1
SEC_SCHEME_VERSION__SecScheme1 = 1,
/*
*!< Security scheme 2 - SRP6a + AES-256-GCM
*/
SEC_SCHEME_VERSION__SecScheme2 = 2
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(SEC_SCHEME_VERSION)
} SecSchemeVersion;
@ -43,7 +48,8 @@ typedef enum _SecSchemeVersion {
typedef enum {
SESSION_DATA__PROTO__NOT_SET = 0,
SESSION_DATA__PROTO_SEC0 = 10,
SESSION_DATA__PROTO_SEC1 = 11
SESSION_DATA__PROTO_SEC1 = 11,
SESSION_DATA__PROTO_SEC2 = 12
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(SESSION_DATA__PROTO__CASE)
} SessionData__ProtoCase;
@ -68,6 +74,10 @@ struct SessionData
*!< Payload data in case of security 1
*/
Sec1Payload *sec1;
/*
*!< Payload data in case of security 2
*/
Sec2Payload *sec2;
};
};
#define SESSION_DATA__INIT \

Wyświetl plik

@ -8,6 +8,7 @@ set(PY_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../python")
set(PROTO_SRCS "constants.proto"
"sec0.proto"
"sec1.proto"
"sec2.proto"
"session.proto")
add_custom_target(c_proto

Wyświetl plik

@ -0,0 +1,48 @@
syntax = "proto3";
import "constants.proto";
/* A message must be of type Cmd0 / Cmd1 / Resp0 / Resp1 */
enum Sec2MsgType {
S2Session_Command0 = 0;
S2Session_Response0 = 1;
S2Session_Command1 = 2;
S2Session_Response1 = 3;
}
// NOTE: Client: Host (shell, Android/iOS) | Device: ESP32-XX
/* Data structure of Session command0 packet */
message S2SessionCmd0 {
bytes client_username = 1;
bytes client_pubkey = 2;
}
/* Data structure of Session response0 packet */
message S2SessionResp0 {
Status status = 1;
bytes device_pubkey = 2;
bytes device_salt = 3;
}
/* Data structure of Session command1 packet */
message S2SessionCmd1 {
bytes client_proof = 1;
}
/* Data structure of Session response1 packet */
message S2SessionResp1 {
Status status = 1;
bytes device_proof = 2;
bytes device_nonce = 3;
}
/* Payload structure of session data */
message Sec2Payload {
Sec2MsgType msg = 1; /*!< Type of message */
oneof payload {
S2SessionCmd0 sc0 = 20; /*!< Payload data interpreted as Cmd0 */
S2SessionResp0 sr0 = 21; /*!< Payload data interpreted as Resp0 */
S2SessionCmd1 sc1 = 22; /*!< Payload data interpreted as Cmd1 */
S2SessionResp1 sr1 = 23; /*!< Payload data interpreted as Resp1 */
}
}

Wyświetl plik

@ -2,12 +2,15 @@ syntax = "proto3";
import "sec0.proto";
import "sec1.proto";
import "sec2.proto";
/* Allowed values for the type of security
* being used in a protocomm session */
enum SecSchemeVersion {
SecScheme0 = 0; /*!< Unsecured - plaintext communication */
SecScheme1 = 1; /*!< Security scheme 1 - Curve25519 + AES-256-CTR*/
SecScheme0 = 0; /*!< Unsecured - plaintext communication */
SecScheme1 = 1; /*!< Security scheme 1 - Curve25519 + AES-256-CTR*/
SecScheme2 = 2; /*!< Security scheme 2 - SRP6a + AES-256-GCM*/
}
/* Data structure exchanged when establishing
@ -17,5 +20,6 @@ message SessionData {
oneof proto {
Sec0Payload sec0 = 10; /*!< Payload data in case of security 0 */
Sec1Payload sec1 = 11; /*!< Payload data in case of security 1 */
Sec2Payload sec2 = 12; /*!< Payload data in case of security 2 */
}
}

Wyświetl plik

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: sec2.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
import constants_pb2 as constants__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nsec2.proto\x1a\x0f\x63onstants.proto\"?\n\rS2SessionCmd0\x12\x17\n\x0f\x63lient_username\x18\x01 \x01(\x0c\x12\x15\n\rclient_pubkey\x18\x02 \x01(\x0c\"U\n\x0eS2SessionResp0\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\x15\n\rdevice_pubkey\x18\x02 \x01(\x0c\x12\x13\n\x0b\x64\x65vice_salt\x18\x03 \x01(\x0c\"%\n\rS2SessionCmd1\x12\x14\n\x0c\x63lient_proof\x18\x01 \x01(\x0c\"U\n\x0eS2SessionResp1\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\x14\n\x0c\x64\x65vice_proof\x18\x02 \x01(\x0c\x12\x14\n\x0c\x64\x65vice_nonce\x18\x03 \x01(\x0c\"\xb1\x01\n\x0bSec2Payload\x12\x19\n\x03msg\x18\x01 \x01(\x0e\x32\x0c.Sec2MsgType\x12\x1d\n\x03sc0\x18\x14 \x01(\x0b\x32\x0e.S2SessionCmd0H\x00\x12\x1e\n\x03sr0\x18\x15 \x01(\x0b\x32\x0f.S2SessionResp0H\x00\x12\x1d\n\x03sc1\x18\x16 \x01(\x0b\x32\x0e.S2SessionCmd1H\x00\x12\x1e\n\x03sr1\x18\x17 \x01(\x0b\x32\x0f.S2SessionResp1H\x00\x42\t\n\x07payload*o\n\x0bSec2MsgType\x12\x16\n\x12S2Session_Command0\x10\x00\x12\x17\n\x13S2Session_Response0\x10\x01\x12\x16\n\x12S2Session_Command1\x10\x02\x12\x17\n\x13S2Session_Response1\x10\x03\x62\x06proto3')
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'sec2_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_SEC2MSGTYPE._serialized_start=489
_SEC2MSGTYPE._serialized_end=600
_S2SESSIONCMD0._serialized_start=31
_S2SESSIONCMD0._serialized_end=94
_S2SESSIONRESP0._serialized_start=96
_S2SESSIONRESP0._serialized_end=181
_S2SESSIONCMD1._serialized_start=183
_S2SESSIONCMD1._serialized_end=220
_S2SESSIONRESP1._serialized_start=222
_S2SESSIONRESP1._serialized_end=307
_SEC2PAYLOAD._serialized_start=310
_SEC2PAYLOAD._serialized_end=487
# @@protoc_insertion_point(module_scope)

Wyświetl plik

@ -13,17 +13,18 @@ _sym_db = _symbol_database.Default()
import sec0_pb2 as sec0__pb2
import sec1_pb2 as sec1__pb2
import sec2_pb2 as sec2__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rsession.proto\x1a\nsec0.proto\x1a\nsec1.proto\"v\n\x0bSessionData\x12\"\n\x07sec_ver\x18\x02 \x01(\x0e\x32\x11.SecSchemeVersion\x12\x1c\n\x04sec0\x18\n \x01(\x0b\x32\x0c.Sec0PayloadH\x00\x12\x1c\n\x04sec1\x18\x0b \x01(\x0b\x32\x0c.Sec1PayloadH\x00\x42\x07\n\x05proto*2\n\x10SecSchemeVersion\x12\x0e\n\nSecScheme0\x10\x00\x12\x0e\n\nSecScheme1\x10\x01\x62\x06proto3')
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rsession.proto\x1a\nsec0.proto\x1a\nsec1.proto\x1a\nsec2.proto\"\x94\x01\n\x0bSessionData\x12\"\n\x07sec_ver\x18\x02 \x01(\x0e\x32\x11.SecSchemeVersion\x12\x1c\n\x04sec0\x18\n \x01(\x0b\x32\x0c.Sec0PayloadH\x00\x12\x1c\n\x04sec1\x18\x0b \x01(\x0b\x32\x0c.Sec1PayloadH\x00\x12\x1c\n\x04sec2\x18\x0c \x01(\x0b\x32\x0c.Sec2PayloadH\x00\x42\x07\n\x05proto*B\n\x10SecSchemeVersion\x12\x0e\n\nSecScheme0\x10\x00\x12\x0e\n\nSecScheme1\x10\x01\x12\x0e\n\nSecScheme2\x10\x02\x62\x06proto3')
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'session_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_SECSCHEMEVERSION._serialized_start=161
_SECSCHEMEVERSION._serialized_end=211
_SESSIONDATA._serialized_start=41
_SESSIONDATA._serialized_end=159
_SECSCHEMEVERSION._serialized_start=204
_SECSCHEMEVERSION._serialized_end=270
_SESSIONDATA._serialized_start=54
_SESSIONDATA._serialized_end=202
# @@protoc_insertion_point(module_scope)

Wyświetl plik

@ -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");
if (pc->sec && pc->sec->cleanup) {
pc->sec->cleanup(pc->sec_inst);
pc->sec_inst = NULL;
pc->sec = NULL;
/* 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;
}
protocomm_remove_endpoint(pc, ep_name);
return ESP_ERR_NO_MEM;
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;
}
memcpy((void *)pc->pop, pop, sizeof(protocomm_security_pop_t));
}
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 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);

Wyświetl plik

@ -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;

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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);

Wyświetl plik

@ -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);

Wyświetl plik

@ -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,
};

Wyświetl plik

@ -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)
};

Wyświetl plik

@ -199,9 +199,19 @@ typedef enum wifi_prov_security {
* + proof of possession (pop) based authentication
* + AES-CTR encryption
*/
WIFI_PROV_SECURITY_1
WIFI_PROV_SECURITY_1,
/**
* This secure communication mode consists of
* SRP6a based authentication and key exchange
* + AES-GCM encryption/decryption
*/
WIFI_PROV_SECURITY_2
} wifi_prov_security_t;
typedef protocomm_security1_params_t wifi_prov_security1_params_t;
typedef protocomm_security2_params_t wifi_prov_security2_params_t;
/**
* @brief Initialize provisioning manager instance
*
@ -283,9 +293,14 @@ esp_err_t wifi_prov_mgr_is_provisioned(bool *provisioned);
* - WIFI_PROV_SECURITY_0 : For no security
* - WIFI_PROV_SECURITY_1 : x25519 secure handshake for session
* establishment followed by AES-CTR encryption of provisioning messages
* @param[in] pop Pointer to proof of possession string (NULL if not needed). This
* is relevant only for protocomm security 1, in which case it is used
* for authenticating secure session
* - WIFI_PROV_SECURITY_2: SRP6a based authentication and key exchange
* followed by AES-GCM encryption/decryption of provisioning messages
* @param[in] wifi_prov_sec_params
* Pointer to security params (NULL if not needed).
* This is not needed for protocomm security 0
* This pointer should hold the struct of type
* wifi_prov_security1_params_t for protocomm security 1
* and wifi_prov_security2_params_t for protocomm security 2 respectively.
* @param[in] service_name Unique name of the service. This translates to:
* - Wi-Fi SSID when provisioning mode is softAP
* - Device name when provisioning mode is BLE
@ -299,8 +314,7 @@ 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 void *wifi_prov_sec_params, const char *service_name, const char *service_key);
/**
* @brief Stop provisioning service

Wyświetl plik

@ -21,6 +21,7 @@
#include <protocomm.h>
#include <protocomm_security0.h>
#include <protocomm_security1.h>
#include <protocomm_security2.h>
#include "wifi_provisioning_priv.h"
@ -90,8 +91,8 @@ struct wifi_prov_mgr_ctx {
/* Type of security to use with protocomm */
int security;
/* Pointer to proof of possession */
protocomm_security_pop_t pop;
/* Pointer to security params */
const void* protocomm_sec_params;
/* Handle for Provisioning Auto Stop timer */
esp_timer_handle_t autostop_timer;
@ -306,11 +307,29 @@ 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) {
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0
ret = protocomm_set_security(prov_ctx->pc, "prov-session",
&protocomm_security0, NULL);
#else
// Enable SECURITY_VERSION_0 in Protocomm configuration menu
return ESP_ERR_NOT_SUPPORTED;
#endif
} else if (prov_ctx->security == 1) {
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1
ret = protocomm_set_security(prov_ctx->pc, "prov-session",
&protocomm_security1, &prov_ctx->pop);
&protocomm_security1, prov_ctx->protocomm_sec_params);
#else
// Enable SECURITY_VERSION_1 in Protocomm configuration menu
return ESP_ERR_NOT_SUPPORTED;
#endif
} else if (prov_ctx->security == 2) {
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2
ret = protocomm_set_security(prov_ctx->pc, "prov-session",
&protocomm_security2, prov_ctx->protocomm_sec_params);
#else
// Enable SECURITY_VERSION_2 in Protocomm configuration menu
return ESP_ERR_NOT_SUPPORTED;
#endif
} else {
ESP_LOGE(TAG, "Unsupported protocomm security version %d", prov_ctx->security);
ret = ESP_ERR_INVALID_ARG;
@ -580,9 +599,8 @@ static bool wifi_prov_mgr_stop_service(bool blocking)
prov_ctx->prov_state = WIFI_PROV_STATE_STOPPING;
/* Free proof of possession */
if (prov_ctx->pop.data) {
free((void *)prov_ctx->pop.data);
prov_ctx->pop.data = NULL;
if (prov_ctx->protocomm_sec_params) {
prov_ctx->protocomm_sec_params = NULL;
}
/* Delete all scan results */
@ -1330,6 +1348,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,9 +1399,11 @@ 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,
esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const void *wifi_prov_sec_params,
const char *service_name, const char *service_key)
{
uint8_t restore_wifi_flag = 0;
@ -1459,17 +1480,16 @@ 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) {
prov_ctx->pop.len = strlen(pop);
prov_ctx->pop.data = malloc(prov_ctx->pop.len);
if (!prov_ctx->pop.data) {
ESP_LOGE(TAG, "Unable to allocate PoP data");
ret = ESP_ERR_NO_MEM;
goto err;
} else if (security == WIFI_PROV_SECURITY_1) {
if (wifi_prov_sec_params) {
prov_ctx->protocomm_sec_params = wifi_prov_sec_params;
} else {
prov_ctx->mgr_info.capabilities.no_pop = true;
}
} else if (security == WIFI_PROV_SECURITY_2) {
if (wifi_prov_sec_params) {
prov_ctx->protocomm_sec_params = wifi_prov_sec_params;
}
memcpy((void *)prov_ctx->pop.data, pop, prov_ctx->pop.len);
} else {
prov_ctx->mgr_info.capabilities.no_pop = true;
}
prov_ctx->security = security;
@ -1483,7 +1503,6 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const
ret = esp_timer_create(&wifi_connect_timer_conf, &prov_ctx->wifi_connect_timer);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to create Wi-Fi connect timer");
free((void *)prov_ctx->pop.data);
goto err;
}
@ -1500,7 +1519,6 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to create auto-stop timer");
esp_timer_delete(prov_ctx->wifi_connect_timer);
free((void *)prov_ctx->pop.data);
goto err;
}
}
@ -1516,7 +1534,6 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const
if (ret != ESP_OK) {
esp_timer_delete(prov_ctx->autostop_timer);
esp_timer_delete(prov_ctx->wifi_connect_timer);
free((void *)prov_ctx->pop.data);
}
ACQUIRE_LOCK(prov_ctx_lock);
if (ret == ESP_OK) {

Wyświetl plik

@ -91,9 +91,12 @@ Similarly for HTTPS transport:
You may set security for transport in ESP local control using following options:
1. `PROTOCOM_SEC1`: specifies that end to end encryption is used.
2. `PROTOCOM_SEC0`: specifies that data will be exchanged as a plain text.
3. `PROTOCOM_SEC_CUSTOM`: you can define your own security requirement. Please note that you will also have to provide `custom_handle` of type `protocomm_security_t *` in this context.
1. `PROTOCOM_SEC2`: specifies that SRP6a based key exchange and end to end encryption based on AES-GCM is used. This is the most preffered option as it adds a robust security with Augmented PAKE protocol i.e. SRP6a.
2. `PROTOCOM_SEC1`: specifies that Curve25519 based key exchange and end to end encryption based on AES-CTR is used.
3. `PROTOCOM_SEC0`: specifies that data will be exchanged as a plain text (no security).
4. `PROTOCOM_SEC_CUSTOM`: you can define your own security requirement. Please note that you will also have to provide `custom_handle` of type `protocomm_security_t *` in this context.
.. note:: The respective security schemes need to be enabled through the project configuration menu. Please refer to the Enabling protocom security version section in :doc:`Protocol Communication </api-reference/provisioning/protocomm>` for more details.
Creating a property
-------------------

Wyświetl plik

@ -8,14 +8,146 @@ Protocol Communication (protocomm) component manages secure sessions and provide
Following features are available for provisioning :
* Communication security at application level -
* protocomm_security0 (no security)
* protocomm_security1 (curve25519 key exchange + AES-CTR encryption)
* protocomm_security1 (Curve25519 key exchange + AES-CTR encryption/decryption)
* protocomm_security2 (SRP6a-based key exchange + AES-GCM encryption/decryption)
* Proof-of-possession (support with protocomm_security1 only)
* Salt and Verifier (support with protocomm_security2 only)
Protocomm internally uses protobuf (protocol buffers) for secure session establishment. Though users can implement their own security (even without using protobuf). One can even use protocomm without any security layer.
Protocomm provides framework for various transports - WiFi (SoftAP+HTTPD), BLE, console - in which case the handler invocation is automatically taken care of on the device side (see Transport Examples below for code snippets).
Note that the client still needs to establish session (only for protocomm_security1) by performing the two way handshake. See :doc:`provisioning` for more details about the secure handshake logic.
Note that the client still needs to establish session (for protocomm_security1 and protocomm_security2) by performing the two way handshake. See :doc:`provisioning` for more details about the secure handshake logic.
Enabling protocomm security version
-----------------------------------
Protocomm component provides project configuration menu to enable/disable support of respective security versions.
The respective configuration options can be found as follows:
* Support protocomm security version 1 (no security): :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0` (this option is enabled by default)
* Support protocomm security version 1 (Curve25519 key exchange + AES-CTR encryption/decryption): :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1` (this option is enabled by default)
* Support protocomm security version 2 (SRP6a-based key exchange + AES-GCM encryption/decryption): :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2`
.. note:: Enabling multiple security versions allow to control them dynamically but also increases firmware size.
Transport Example (SoftAP + HTTP) with Security 2
-------------------------------------------------
For sample usage, see :component_file:`wifi_provisioning/src/scheme_softap.c`
.. highlight:: c
::
/* Endpoint handler to be registered with protocomm.
* This simply echoes back the received data. */
esp_err_t echo_req_handler (uint32_t session_id,
const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen,
void *priv_data)
{
/* Session ID may be used for persistence */
printf("Session ID : %d", session_id);
/* Echo back the received data */
*outlen = inlen; /* Output data length updated */
*outbuf = malloc(inlen); /* This will be deallocated outside */
memcpy(*outbuf, inbuf, inlen);
/* Private data that was passed at the time of endpoint creation */
uint32_t *priv = (uint32_t *) priv_data;
if (priv) {
printf("Private data : %d", *priv);
}
return ESP_OK;
}
static const char sec2_salt[] = {0xf7, 0x5f, 0xe2, 0xbe, 0xba, 0x7c, 0x81, 0xcd};
static const char sec2_verifier[] = {0xbf, 0x86, 0xce, 0x63, 0x8a, 0xbb, 0x7e, 0x2f, 0x38, 0xa8, 0x19, 0x1b, 0x35,
0xc9, 0xe3, 0xbe, 0xc3, 0x2b, 0x45, 0xee, 0x10, 0x74, 0x22, 0x1a, 0x95, 0xbe, 0x62, 0xf7, 0x0c, 0x65, 0x83, 0x50,
0x08, 0xef, 0xaf, 0xa5, 0x94, 0x4b, 0xcb, 0xe1, 0xce, 0x59, 0x2a, 0xe8, 0x7b, 0x27, 0xc8, 0x72, 0x26, 0x71, 0xde,
0xb2, 0xf2, 0x80, 0x02, 0xdd, 0x11, 0xf0, 0x38, 0x0e, 0x95, 0x25, 0x00, 0xcf, 0xb3, 0x3f, 0xf0, 0x73, 0x2a, 0x25,
0x03, 0xe8, 0x51, 0x72, 0xef, 0x6d, 0x3e, 0x14, 0xb9, 0x2e, 0x9f, 0x2a, 0x90, 0x9e, 0x26, 0xb6, 0x3e, 0xc7, 0xe4,
0x9f, 0xe3, 0x20, 0xce, 0x28, 0x7c, 0xbf, 0x89, 0x50, 0xc9, 0xb6, 0xec, 0xdd, 0x81, 0x18, 0xf1, 0x1a, 0xd9, 0x7a,
0x21, 0x99, 0xf1, 0xee, 0x71, 0x2f, 0xcc, 0x93, 0x16, 0x34, 0x0c, 0x79, 0x46, 0x23, 0xe4, 0x32, 0xec, 0x2d, 0x9e,
0x18, 0xa6, 0xb9, 0xbb, 0x0a, 0xcf, 0xc4, 0xa8, 0x32, 0xc0, 0x1c, 0x32, 0xa3, 0x97, 0x66, 0xf8, 0x30, 0xb2, 0xda,
0xf9, 0x8d, 0xc3, 0x72, 0x72, 0x5f, 0xe5, 0xee, 0xc3, 0x5c, 0x24, 0xc8, 0xdd, 0x54, 0x49, 0xfc, 0x12, 0x91, 0x81,
0x9c, 0xc3, 0xac, 0x64, 0x5e, 0xd6, 0x41, 0x88, 0x2f, 0x23, 0x66, 0xc8, 0xac, 0xb0, 0x35, 0x0b, 0xf6, 0x9c, 0x88,
0x6f, 0xac, 0xe1, 0xf4, 0xca, 0xc9, 0x07, 0x04, 0x11, 0xda, 0x90, 0x42, 0xa9, 0xf1, 0x97, 0x3d, 0x94, 0x65, 0xe4,
0xfb, 0x52, 0x22, 0x3b, 0x7a, 0x7b, 0x9e, 0xe9, 0xee, 0x1c, 0x44, 0xd0, 0x73, 0x72, 0x2a, 0xca, 0x85, 0x19, 0x4a,
0x60, 0xce, 0x0a, 0xc8, 0x7d, 0x57, 0xa4, 0xf8, 0x77, 0x22, 0xc1, 0xa5, 0xfa, 0xfb, 0x7b, 0x91, 0x3b, 0xfe, 0x87,
0x5f, 0xfe, 0x05, 0xd2, 0xd6, 0xd3, 0x74, 0xe5, 0x2e, 0x68, 0x79, 0x34, 0x70, 0x40, 0x12, 0xa8, 0xe1, 0xb4, 0x6c,
0xaa, 0x46, 0x73, 0xcd, 0x8d, 0x17, 0x72, 0x67, 0x32, 0x42, 0xdc, 0x10, 0xd3, 0x71, 0x7e, 0x8b, 0x00, 0x46, 0x9b,
0x0a, 0xe9, 0xb4, 0x0f, 0xeb, 0x70, 0x52, 0xdd, 0x0a, 0x1c, 0x7e, 0x2e, 0xb0, 0x61, 0xa6, 0xe1, 0xa3, 0x34, 0x4b,
0x2a, 0x3c, 0xc4, 0x5d, 0x42, 0x05, 0x58, 0x25, 0xd3, 0xca, 0x96, 0x5c, 0xb9, 0x52, 0xf9, 0xe9, 0x80, 0x75, 0x3d,
0xc8, 0x9f, 0xc7, 0xb2, 0xaa, 0x95, 0x2e, 0x76, 0xb3, 0xe1, 0x48, 0xc1, 0x0a, 0xa1, 0x0a, 0xe8, 0xaf, 0x41, 0x28,
0xd2, 0x16, 0xe1, 0xa6, 0xd0, 0x73, 0x51, 0x73, 0x79, 0x98, 0xd9, 0xb9, 0x00, 0x50, 0xa2, 0x4d, 0x99, 0x18, 0x90,
0x70, 0x27, 0xe7, 0x8d, 0x56, 0x45, 0x34, 0x1f, 0xb9, 0x30, 0xda, 0xec, 0x4a, 0x08, 0x27, 0x9f, 0xfa, 0x59, 0x2e,
0x36, 0x77, 0x00, 0xe2, 0xb6, 0xeb, 0xd1, 0x56, 0x50, 0x8e};
/* Example function for launching a protocomm instance over HTTP */
protocomm_t *start_pc()
{
protocomm_t *pc = protocomm_new();
/* Config for protocomm_httpd_start() */
protocomm_httpd_config_t pc_config = {
.data = {
.config = PROTOCOMM_HTTPD_DEFAULT_CONFIG()
}
};
/* Start protocomm server on top of HTTP */
protocomm_httpd_start(pc, &pc_config);
/* Create Security2 params object from salt and verifier. It must be valid
* throughout the scope of protocomm endpoint. This need not be static,
* ie. could be dynamically allocated and freed at the time of endpoint
* removal */
const static protocomm_security2_params_t sec2_params = {
.salt = (const uint8_t *) salt,
.salt_len = sizeof(salt),
.verifier = (const uint8_t *) verifier,
.verifier_len = sizeof(verifier),
};
/* Set security for communication at application level. Just like for
* request handlers, setting security creates an endpoint and registers
* the handler provided by protocomm_security1. One can similarly use
* protocomm_security0. Only one type of security can be set for a
* protocomm instance at a time. */
protocomm_set_security(pc, "security_endpoint", &protocomm_security2, &sec2_params);
/* Private data passed to the endpoint must be valid throughout the scope
* of protocomm endpoint. This need not be static, ie. could be dynamically
* allocated and freed at the time of endpoint removal */
static uint32_t priv_data = 1234;
/* Add a new endpoint for the protocomm instance, identified by a unique name
* and register a handler function along with private data to be passed at the
* time of handler execution. Multiple endpoints can be added as long as they
* are identified by unique names */
protocomm_add_endpoint(pc, "echo_req_endpoint",
echo_req_handler, (void *) &priv_data);
return pc;
}
/* Example function for stopping a protocomm instance */
void stop_pc(protocomm_t *pc)
{
/* Remove endpoint identified by it's unique name */
protocomm_remove_endpoint(pc, "echo_req_endpoint");
/* Remove security endpoint identified by it's name */
protocomm_unset_security(pc, "security_endpoint");
/* Stop HTTP server */
protocomm_httpd_stop(pc);
/* Delete (deallocate) the protocomm instance */
protocomm_delete(pc);
}
Transport Example (SoftAP + HTTP) with Security 1
-------------------------------------------------
@ -65,11 +197,11 @@ For sample usage, see :component_file:`wifi_provisioning/src/scheme_softap.c`
/* Start protocomm server on top of HTTP */
protocomm_httpd_start(pc, &pc_config);
/* Create Proof of Possession object from pop_string. It must be valid
/* Create security1 params object from pop_string. It must be valid
* throughout the scope of protocomm endpoint. This need not be static,
* ie. could be dynamically allocated and freed at the time of endpoint
* removal */
const static protocomm_security_pop_t pop_obj = {
const static protocomm_security1_params_t sec1_params = {
.data = (const uint8_t *) strdup(pop_string),
.len = strlen(pop_string)
};
@ -79,7 +211,7 @@ For sample usage, see :component_file:`wifi_provisioning/src/scheme_softap.c`
* the handler provided by protocomm_security1. One can similarly use
* protocomm_security0. Only one type of security can be set for a
* protocomm instance at a time. */
protocomm_set_security(pc, "security_endpoint", &protocomm_security1, &pop_obj);
protocomm_set_security(pc, "security_endpoint", &protocomm_security1, &sec1_params);
/* Private data passed to the endpoint must be valid throughout the scope
* of protocomm endpoint. This need not be static, ie. could be dynamically

Wyświetl plik

@ -99,14 +99,20 @@ Application creates a protocomm instance which is mapped to a specific transport
Security Schemes
>>>>>>>>>>>>>>>>
At present unified provisioning supports two security schemes:
1. Security0 - No security (No encryption)
2. Security1 - Curve25519 based key exchange, shared key derivation and AES256-CTR mode encryption of the data. It supports two modes :
At present, unified provisioning supports the following security schemes:
1. Security0 - No security (No encryption)
2. Security1 - Curve25519-based key exchange, shared key derivation and AES256-CTR mode encryption of the data. It supports two modes :
a. Authorized - Proof of Possession (PoP) string used to authorize session and derive shared key
b. No Auth (Null PoP) - Shared key derived through key exchange only
3. Security2 - SRP6a-based shared key derivation and AES256-GCM mode encryption of the data.
Security1 scheme details are shown in the below sequence diagram
.. note:: The respective security schemes need to be enabled through the project configuration menu. Please refer to the Enabling protocom security version section in :doc:`protocomm` (Protocol Communication) for more details.
Security1 Scheme
>>>>>>>>>>>>>>>>
Security1 scheme details are shown in the below sequence diagram -
.. seqdiag::
:caption: Security1
@ -140,6 +146,71 @@ Security1 scheme details are shown in the below sequence diagram
CLIENT -> CLIENT [label = "Verify Device", rightnote = "check (cli_pubkey == aes_ctr_dec(dev_verify...)"];
}
.. note:: We shall soon migrate to ``Security2 scheme`` as the default scheme in our examples as it provides enhanced security. This change shall be done once we have our phone apps (Android/iOS) upgraded to handle ``Security2 scheme``.
Security2 Scheme
>>>>>>>>>>>>>>>>
Security2 scheme is based on the Secure Remote Password (SRP6a) protocol - `RFC 5054 <https://datatracker.ietf.org/doc/html/rfc5054>`_.
The protocol requires the Salt and Verifier to be generated beforehand with help of the identifying username ``I`` and the plaintext password ``p``. The Salt and Verifier are then stored on {IDF_TARGET_NAME}.
- The password ``p`` and username ``I`` are to be provided to the Phone App (Provisioning entity) by suitable means for example QR code sticker.
Security2 scheme details are shown in the below sequence diagram -
.. seqdiag::
:caption: Security2
:align: center
seqdiag security2 {
activation = none;
node_width = 80;
node_height = 60;
edge_length = 550;
span_height = 5;
default_shape = roundedbox;
default_fontsize = 12;
CLIENT [label = "Client\n(PhoneApp)"];
DEVICE [label = "Device\n(ESP)"];
=== Security 2 ===
CLIENT -> CLIENT [label = "Generate\nKey Pair", rightnote = "a (cli_privkey) = 256 bit random value,
A (cli_pubkey) = g^a.
g - generator, N - large safe prime,
All arithmetic operations are performed in ring of integers modulo N,
thus all occurrences like y^z should be read as y^z modulo N."];
CLIENT -> DEVICE [label = "SessionCmd0(cli_pubkey A, username I)"];
DEVICE -> DEVICE [label = "Obtain\n Salt and Verifier", leftnote = "Obtain salt and verifier stored on esp
Salt s = 256 bit random value,
Verifier v = g^x where x = H(s | I | p)"];
DEVICE -> DEVICE [label = "Generate\nKey Pair", leftnote = "b (dev_privkey) = 256 bit random value
B(dev_pubkey) = k*v + g^b where k = H(N, g)"];
DEVICE -> DEVICE [label = "Shared Key", leftnote = "Shared Key K = H(S) where,
S = (A * v^u) ^ b
u = H(A, B)"];
DEVICE -> CLIENT [label = "SessionResp0(dev_pubkey B, dev_rand)"];
CLIENT -> CLIENT [label = "Shared Key", rightnote = "shared_key(K) = H(S) where,
S = (B - k*v) ^ (a + ux),
u = H(A, B),
k = H(N, g),
v = g^x,
x = H(s | I | p).
"];
CLIENT -> CLIENT [label = "Verification\nToken", rightnote = "client_proof M = H[H(N) XOR H(g) | H(I) | s | A | B | K]"];
CLIENT -> DEVICE [label = "SessionCmd1(client_proof M1)"];
DEVICE -> DEVICE [label = "Verify Client", leftnote = "device generates M1 = H[H(N) XOR H(g) | H(I) | s | A | B | K]
device verifies this M1 with the M1 obtained from Client"];
DEVICE -> DEVICE [label = "Verification\nToken", leftnote = "
Device generate device_proof M2 = H(A, M, K)"];
DEVICE -> DEVICE [label = "Initialization\nVector", leftnote = "dev_rand = gen_16byte_random()
This random number is to be used for AES-GCM operation
for encryption and decryption of data using the shared secret"];
DEVICE -> CLIENT [label = "SessionResp1(device_proof M2, dev_rand)"];
CLIENT -> CLIENT [label = "Verify Device", rightnote = "Client calculates device proof M2 as M2 = H(A, M, K)
client verifies this M2 with M2 obtained from device"];
}
Sample Code
>>>>>>>>>>>
Please refer to :doc:`protocomm` and :doc:`wifi_provisioning` for API guides and code snippets on example usage.

Wyświetl plik

@ -11,6 +11,7 @@ ESP-IDF 5.0 Migration Guides
freertos
peripherals
protocols
provisioning
removed-components
storage
system

Wyświetl plik

@ -0,0 +1,25 @@
Migrate Provisioning to ESP-IDF 5.0
===================================
Protocomm
---------
The :cpp:func:`protocomm_set_security` API now takes a parameter ``sec_params`` as input instead of ``pop`` (deprecated).
This parameter should contain the structure (containing the security parameters) as required by the protocol version used.
For example when using security version 2, the ``sec_params`` parameter should contain the pointer to the structure of type :cpp:type:`protocomm_security2_params_t`.
Wi-Fi Provisioning
------------------
The :cpp:func:`wifi_prov_mgr_start_provisioning` API now takes a parameter ``wifi_prov_sec_params`` as input instead of ``pop``.
This parameter should contain the structure (containing the security parameters) as required by the protocol version used.
For example when using security version 2, the ``wifi_prov_sec_params`` parameter should contain the pointer to the structure of type :cpp:type:`wifi_prov_security2_params_t`.
ESP Local Control
-----------------
The `pop` field in :cpp:type:`esp_local_ctrl_proto_sec_cfg_t` is now deprecated, use ``sec_params`` field instead of ``pop``.
This field should contain the structure (containing the security parameters) as required by the protocol version used.
For example when using security version 2, the ``sec_params`` field should contain pointer to the structure of type :cpp:type:`esp_local_ctrl_security2_params_t`.

Wyświetl plik

@ -11,6 +11,7 @@ ESP-IDF 5.0 迁移指南
freertos
peripherals
protocols
provisioning
removed-components
storage
system

Wyświetl plik

@ -0,0 +1 @@
.. include:: ../../en/migration-guides/provisioning.rst

Wyświetl plik

@ -181,7 +181,7 @@ void start_esp_local_ctrl_service(void)
.proto_sec = {
.version = 0,
.custom_handle = NULL,
.pop = NULL,
.sec_params = NULL,
},
.handlers = {
/* User defined handler functions */

Wyświetl plik

@ -79,10 +79,10 @@ I (1045) wifi_prov_mgr: Provisioning started with service name : PROV_261FCC
Make sure to note down the BLE device name (starting with `PROV_`) displayed in the serial monitor log (eg. PROV_261FCC). This will depend on the MAC ID and will be unique for every device.
In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (make sure to replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). Assuming default example configuration, which uses protocomm security scheme 1 and proof of possession PoP based authentication :
In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (make sure to replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). Assuming default example configuration, which uses the protocomm security scheme 2 (based on Secure Remote Password protocol (SRP6a)) :
```
python esp_prov.py --transport ble --service_name PROV_261FCC --sec_ver 1 --pop abcd1234 --ssid myssid --passphrase mypassword
python esp_prov.py --verbose --transport ble --service_name PROV_4C33E8 --sec_ver 2 --sec2_username testuser --sec2_pwd testpassword --ssid myssid --passphrase mypassword
```
Above command will perform the provisioning steps, and the monitor log should display something like this :
@ -114,6 +114,26 @@ I (54355) app: Hello World!
I (55355) app: Hello World!
```
**Note:** For generating the credentials for security version 2 (`SRP6a` salt and verifier) for the device-side, the following example command can be used. The output can then directly be used in this example.
The config option `CONFIG_EXAMPLE_PROV_SEC2_USERNAME` should be set to the same username used in the salt-verifier generation.
```log
$ python esp_prov.py --verbose --transport softap --sec_ver 2 --sec2_gen_cred --sec2_username testuser --sec2_pwd testpassword
==== Salt-verifier for security scheme 2 (SRP6a) ====
static const char sec2_salt[] = {
0x14, 0xdf, 0x42, 0x50, 0x3d, 0xec, 0x54, 0xc3, 0xe5, 0x0e, 0x0c, 0x9d, 0xb4, 0x84, 0xd7, 0xe4
};
static const char sec2_verifier[] = {
0xd7, 0xc2, 0xdb, 0x68, 0x3b, 0x98, 0xf0, 0xbf, 0x4f, 0x02, 0x21, 0xf6, 0x07, 0xe6, 0xfc, 0x0d,
...
...
0x86, 0xf2, 0x78, 0xba, 0x1e, 0x12, 0xa9, 0x62, 0x9a, 0x47, 0x1b, 0x69, 0x42, 0xba, 0x37, 0xe2
};
```
### QR Code Scanning
Enabling `CONFIG_EXAMPLE_PROV_SHOW_QR` will display a QR code on the serial terminal, which can be scanned from the ESP Provisioning phone apps to start the Wi-Fi provisioning process.

Wyświetl plik

@ -15,6 +15,43 @@ menu "Example Configuration"
bool "Soft AP"
endchoice
choice EXAMPLE_PROV_SECURITY_VERSION
bool "Protocomm security version"
default EXAMPLE_PROV_SECURITY_VERSION_1
help
Wi-Fi provisioning component offers 3 security versions.
The example offers a choice between security version 1 and 2.
config EXAMPLE_PROV_SECURITY_VERSION_1
bool "Security version 1"
select ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1
config EXAMPLE_PROV_SECURITY_VERSION_2
bool "Security version 2"
select ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2
endchoice
choice EXAMPLE_PROV_MODE
bool "Security version 2 mode"
depends on EXAMPLE_PROV_SECURITY_VERSION_2
default EXAMPLE_PROV_SEC2_DEV_MODE
config EXAMPLE_PROV_SEC2_DEV_MODE
bool "Security version 2 development mode"
depends on EXAMPLE_PROV_SECURITY_VERSION_2
help
This enables the development mode for
security version 2.
Please note that this mode is NOT recommended for production purpose.
config EXAMPLE_PROV_SEC2_PROD_MODE
bool "Security version 2 production mode"
depends on EXAMPLE_PROV_SECURITY_VERSION_2
help
This enables the production mode for
security version 2.
endchoice
config EXAMPLE_PROV_TRANSPORT
int
default 1 if EXAMPLE_PROV_TRANSPORT_BLE

Wyświetl plik

@ -32,6 +32,72 @@
static const char *TAG = "app";
#if CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2
#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE
#define EXAMPLE_PROV_SEC2_USERNAME "testuser"
#define EXAMPLE_PROV_SEC2_PWD "testpassword"
/* This salt,verifier has been generated for username = "testuser" and password = "testpassword"
* IMPORTANT NOTE: For production cases, this must be unique to every device
* and should come from device manufacturing partition.*/
static const char sec2_salt[] = {
0x2f, 0x3d, 0x3c, 0xf8, 0x0d, 0xbd, 0x0c, 0xa9, 0x6f, 0x30, 0xb4, 0x4d, 0x89, 0xd5, 0x2f, 0x0e
};
static const char sec2_verifier[] = {
0xf2, 0x9f, 0xc1, 0xf5, 0x28, 0x4a, 0x11, 0x74, 0xb4, 0x24, 0x09, 0x23, 0xd8, 0x27, 0xb7, 0x5a,
0x95, 0x3a, 0x99, 0xed, 0xf4, 0x6e, 0xe9, 0x8c, 0x4f, 0x07, 0xf2, 0xf5, 0x43, 0x3d, 0x7f, 0x9a,
0x11, 0x60, 0x66, 0xaf, 0xcd, 0xa5, 0xf6, 0xfa, 0xcb, 0x06, 0xe9, 0xc5, 0x3f, 0x4d, 0x77, 0x16,
0x4c, 0x68, 0x6d, 0x7f, 0x7c, 0xd7, 0xc7, 0x5a, 0x83, 0xc0, 0xfb, 0x94, 0x2d, 0xa9, 0x60, 0xf0,
0x09, 0x11, 0xa0, 0xe1, 0x95, 0x33, 0xd1, 0x30, 0x7f, 0x82, 0x1b, 0x1b, 0x0f, 0x6d, 0xf1, 0xdc,
0x93, 0x1c, 0x20, 0xa7, 0xc0, 0x8d, 0x48, 0x38, 0xff, 0x46, 0xb9, 0xaf, 0xf7, 0x93, 0x78, 0xae,
0xff, 0xb8, 0x3b, 0xdf, 0x99, 0x7b, 0x64, 0x47, 0x02, 0xba, 0x01, 0x39, 0x0f, 0x5c, 0xd8, 0x4e,
0x6f, 0xc8, 0xd0, 0x82, 0x7f, 0x2d, 0x33, 0x1a, 0x09, 0x65, 0x77, 0x85, 0xbc, 0x8a, 0x84, 0xe0,
0x46, 0x7e, 0x3b, 0x0e, 0x6e, 0x3b, 0xdf, 0x70, 0x17, 0x70, 0x0a, 0xbc, 0x84, 0x67, 0xfa, 0xf9,
0x84, 0x53, 0xda, 0xb4, 0xca, 0x38, 0x71, 0xe4, 0x06, 0xf6, 0x7d, 0xc8, 0x32, 0xbb, 0x91, 0x0c,
0xe7, 0xd3, 0x59, 0xb6, 0x03, 0xed, 0x8e, 0x0d, 0x91, 0x9c, 0x09, 0xd7, 0x6f, 0xd5, 0xca, 0x55,
0xc5, 0x58, 0x0f, 0x95, 0xb5, 0x83, 0x65, 0x6f, 0x2d, 0xbc, 0x94, 0x0f, 0xbb, 0x0f, 0xd3, 0x42,
0xa5, 0xfe, 0x15, 0x7f, 0xf9, 0xa8, 0x16, 0xe6, 0x58, 0x9b, 0x4c, 0x0f, 0xd3, 0x83, 0x2c, 0xac,
0xe4, 0xbf, 0xa3, 0x96, 0x1e, 0xb6, 0x6f, 0x59, 0xe6, 0xd1, 0x0e, 0xd4, 0x27, 0xb6, 0x05, 0x34,
0xec, 0x8c, 0xf8, 0x72, 0xbb, 0x04, 0x7b, 0xa4, 0x49, 0x3d, 0x6d, 0xa9, 0x99, 0xfc, 0x0a, 0x2b,
0xd8, 0x46, 0xa8, 0xd1, 0x46, 0x61, 0x5c, 0x96, 0xd2, 0x43, 0xcd, 0xea, 0x7f, 0x6a, 0x50, 0x59,
0x0d, 0x0e, 0xa1, 0xb3, 0x94, 0x5a, 0x34, 0xe0, 0x1e, 0x95, 0x56, 0x68, 0xb4, 0xbc, 0xf1, 0x08,
0x54, 0xcb, 0x42, 0x41, 0xc6, 0x78, 0xad, 0x71, 0x84, 0x1c, 0x29, 0xb8, 0x33, 0x79, 0x1c, 0x10,
0xdd, 0x07, 0xc8, 0x91, 0x21, 0x85, 0x89, 0x76, 0xd7, 0x37, 0xdf, 0x5b, 0x19, 0x33, 0x4e, 0x17,
0x67, 0x02, 0x0f, 0x1b, 0xb9, 0x2f, 0xa4, 0xdc, 0xdd, 0x75, 0x32, 0x96, 0x87, 0xdd, 0x66, 0xc3,
0x33, 0xc1, 0xfc, 0x4c, 0x27, 0x63, 0xb9, 0x14, 0x72, 0x76, 0x65, 0xb8, 0x90, 0x2b, 0xeb, 0x7a,
0xde, 0x71, 0x97, 0xf3, 0x6b, 0xc9, 0x8e, 0xdf, 0xfc, 0x6e, 0x13, 0xcc, 0x1b, 0x2b, 0x54, 0x1a,
0x6e, 0x3d, 0xe6, 0x1c, 0xec, 0x5d, 0xa1, 0xf1, 0xd4, 0x86, 0x9d, 0xcd, 0xb9, 0xe8, 0x98, 0xf1,
0xe5, 0x16, 0xa5, 0x48, 0xe5, 0xec, 0x12, 0xe8, 0x17, 0xe2, 0x55, 0xb5, 0xb3, 0x7c, 0xce, 0xfd
};
#endif
static esp_err_t example_get_sec2_salt(const char **salt, uint16_t *salt_len) {
#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE
ESP_LOGI(TAG, "Development mode: using hard coded salt");
*salt = sec2_salt;
*salt_len = sizeof(sec2_salt);
return ESP_OK;
#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE
ESP_LOGE(TAG, "Not implemented!");
return ESP_FAIL;
#endif
}
static esp_err_t example_get_sec2_verifier(const char **verifier, uint16_t *verifier_len) {
#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE
ESP_LOGI(TAG, "Development mode: using hard coded verifier");
*verifier = sec2_verifier;
*verifier_len = sizeof(sec2_verifier);
return ESP_OK;
#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE
/* This code needs to be updated with appropriate implementation to provide verifier */
ESP_LOGE(TAG, "Not implemented!");
return ESP_FAIL;
#endif
}
#endif
/* Signal Wi-Fi events on this event-group */
const int WIFI_CONNECTED_EVENT = BIT0;
static EventGroupHandle_t wifi_event_group;
@ -140,7 +206,7 @@ esp_err_t custom_prov_data_handler(uint32_t session_id, const uint8_t *inbuf, ss
return ESP_OK;
}
static void wifi_prov_print_qr(const char *name, const char *pop, const char *transport)
static void wifi_prov_print_qr(const char *name, const char *username, const char *pop, const char *transport)
{
if (!name || !transport) {
ESP_LOGW(TAG, "Cannot generate QR code payload. Data missing.");
@ -148,9 +214,15 @@ static void wifi_prov_print_qr(const char *name, const char *pop, const char *tr
}
char payload[150] = {0};
if (pop) {
#if CONFIG_EXAMPLE_PROV_SECURITY_VERSION_1
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
",\"pop\":\"%s\",\"transport\":\"%s\"}",
PROV_QR_VERSION, name, pop, transport);
#elif CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
",\"username\":\"%s\",\"pop\":\"%s\",\"transport\":\"%s\"}",
PROV_QR_VERSION, name, username, pop, transport);
#endif
} else {
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
",\"transport\":\"%s\"}",
@ -248,11 +320,14 @@ void app_main(void)
char service_name[12];
get_device_service_name(service_name, sizeof(service_name));
/* What is the security level that we want (0 or 1):
#ifdef CONFIG_EXAMPLE_PROV_SECURITY_VERSION_1
/* What is the security level that we want (0, 1, 2):
* - WIFI_PROV_SECURITY_0 is simply plain text communication.
* - WIFI_PROV_SECURITY_1 is secure communication which consists of secure handshake
* using X25519 key exchange and proof of possession (pop) and AES-CTR
* for encryption/decryption of messages.
* - WIFI_PROV_SECURITY_2 SRP6a based authentication and key exchange
* + AES-GCM encryption/decryption of messages
*/
wifi_prov_security_t security = WIFI_PROV_SECURITY_1;
@ -261,7 +336,45 @@ void app_main(void)
* - NULL if not used
*/
const char *pop = "abcd1234";
/* This is the structure for passing security parameters
* for the protocomm security 1.
* This does not need not be static i.e. could be dynamically allocated
*/
wifi_prov_security1_params_t sec1_params = {
.data = (const uint8_t *)pop,
.len = strlen(pop),
};
wifi_prov_security1_params_t *sec_params = &sec1_params;
const char *username = NULL;
#elif CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2
wifi_prov_security_t security = WIFI_PROV_SECURITY_2;
/* The username must be the same one, which has been used in the generation of salt and verifier */
#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE
/* This pop field represents the password that will be used to generate salt and verifier.
* The field is present here in order to generate the QR code containing password.
* In production this password field shall not be stored on the device */
const char *username = EXAMPLE_PROV_SEC2_USERNAME;
const char *pop = EXAMPLE_PROV_SEC2_PWD;
#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE
/* The username and password shall not be embedded in the firmware,
* they should be provided to the user by other means.
* e.g. QR code sticker */
const char *username = NULL;
const char *pop = NULL;
#endif
/* This is the structure for passing security parameters
* for the protocomm security 2.
* This does not need not be static i.e. could be dynamically allocated
*/
wifi_prov_security2_params_t sec2_params = {};
ESP_ERROR_CHECK(example_get_sec2_salt(&sec2_params.salt, &sec2_params.salt_len));
ESP_ERROR_CHECK(example_get_sec2_verifier(&sec2_params.verifier, &sec2_params.verifier_len));
wifi_prov_security2_params_t *sec_params = &sec2_params;
#endif
/* What is the service key (could be NULL)
* This translates to :
* - Wi-Fi password when scheme is wifi_prov_scheme_softap
@ -300,7 +413,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, (const void *) sec_params, 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
@ -315,9 +429,9 @@ void app_main(void)
// wifi_prov_mgr_deinit();
/* Print QR code for provisioning */
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
wifi_prov_print_qr(service_name, pop, PROV_TRANSPORT_BLE);
wifi_prov_print_qr(service_name, username, pop, PROV_TRANSPORT_BLE);
#else /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */
wifi_prov_print_qr(service_name, pop, PROV_TRANSPORT_SOFTAP);
wifi_prov_print_qr(service_name, username, pop, PROV_TRANSPORT_SOFTAP);
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */
} else {
ESP_LOGI(TAG, "Already provisioned, starting Wi-Fi STA");

Wyświetl plik

@ -462,11 +462,9 @@ components/esp_hid/test/test_esp_hid.c
components/esp_hw_support/include/esp_clk.h
components/esp_hw_support/include/soc/esp_himem.h
components/esp_hw_support/include/soc/esp_spiram.h
components/esp_local_ctrl/include/esp_local_ctrl.h
components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.c
components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.h
components/esp_local_ctrl/python/esp_local_ctrl_pb2.py
components/esp_local_ctrl/src/esp_local_ctrl.c
components/esp_local_ctrl/src/esp_local_ctrl_handler.c
components/esp_local_ctrl/src/esp_local_ctrl_priv.h
components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c
@ -1072,10 +1070,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
components/protocomm/include/transports/protocomm_httpd.h
components/protocomm/proto-c/constants.pb-c.c
@ -1084,14 +1078,15 @@ components/protocomm/proto-c/sec0.pb-c.c
components/protocomm/proto-c/sec0.pb-c.h
components/protocomm/proto-c/sec1.pb-c.c
components/protocomm/proto-c/sec1.pb-c.h
components/protocomm/proto-c/sec2.pb-c.c
components/protocomm/proto-c/sec2.pb-c.h
components/protocomm/proto-c/session.pb-c.c
components/protocomm/proto-c/session.pb-c.h
components/protocomm/python/constants_pb2.py
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
@ -2255,7 +2250,6 @@ tools/esp_prov/__init__.py
tools/esp_prov/prov/__init__.py
tools/esp_prov/prov/wifi_prov.py
tools/esp_prov/prov/wifi_scan.py
tools/esp_prov/security/__init__.py
tools/esp_prov/security/security.py
tools/esp_prov/security/security0.py
tools/esp_prov/security/security1.py
@ -2266,7 +2260,6 @@ tools/esp_prov/transport/transport_ble.py
tools/esp_prov/transport/transport_console.py
tools/esp_prov/transport/transport_http.py
tools/esp_prov/utils/__init__.py
tools/esp_prov/utils/convenience.py
tools/find_apps.py
tools/find_build_apps/__init__.py
tools/find_build_apps/cmake.py

Wyświetl plik

@ -1,4 +1,4 @@
# ESP Provisioning Tool
****# ESP Provisioning Tool
# NAME
`esp_prov` - A python based utility for testing the provisioning examples over a host
@ -31,31 +31,54 @@ Usage of `esp-prov` assumes that the provisioning app has specific protocomm end
Sets the verbosity level of output log
* `--transport <mode>`
Three options are available:
* `softap`
For SoftAP + HTTPD based provisioning. This assumes that the device is running in Wi-Fi SoftAP mode and hosts an HTTP server supporting specific endpoint URIs. Also client needs to connect to the device softAP network before running `esp_prov`
* `ble`
For BLE based provisioning (Linux support only. In Windows/macOS it redirects to console). This assumes that the provisioning endpoints are active on the device with specific BLE service UUIDs
* `console`
For debugging via console based provisioning. The client->device commands are printed to STDOUT and device->client messages are accepted via STDIN. This is to be used when device is accepting provisioning commands on UART console.
* `--ssid <AP SSID>` (Optional)
For specifying the SSID of the Wi-Fi AP to which the device is to connect after provisioning. If not provided, scanning is initiated and scan results, as seen by the device, are displayed, of which an SSID can be picked and the corresponding password specified.
* `--passphrase <AP Password>` (Optional)
For specifying the password of the Wi-Fi AP to which the device is to connect after provisioning. Only used when corresponding SSID is provided using `--ssid`
* `--sec_ver <Security version number>`
For specifying version of protocomm endpoint security to use. For now two versions are supported:
* `0` for `protocomm_security0`
* `1` for `protocomm_security1`
* `--pop <Proof of possession string>` (Optional)
For specifying optional Proof of Possession string to use for protocomm endpoint security version 1. This option is ignored when security version 0 is in use
- Three options are available:
* `softap` - for SoftAP + HTTPD based provisioning
* Requires the device to be running in Wi-Fi SoftAP mode and hosting an HTTP server supporting specific endpoint URIs
* The client needs to be connected to the device softAP network before running the `esp_prov` tool.
* `ble` - for BLE based provisioning
* Supports Linux only; on Windows/macOS, it is redirected to console
* Assumes that the provisioning endpoints are active on the device with specific BLE service UUIDs
* `console` - for debugging via console-based provisioning
* The client->device commands are printed to STDOUT and device->client messages are accepted via STDIN.
* This is to be used when the device is accepting provisioning commands on UART console.
* `--service_name <name>` (Optional)
When transport mode is ble, this specifies the BLE device name to which connection is to be established for provisioned.
When transport mode is softap, this specifies the HTTP server hostname / IP which is running the provisioning service, on the SoftAP network of the device which is to be provisioned. This defaults to `192.168.4.1:80` if not specified
- When transport mode is `ble`, this specifies the BLE device name to which connection is to be established for provisioned.
- When transport mode is `softap`, this specifies the HTTP server hostname / IP which is running the provisioning service, on the SoftAP network of the device which is to be provisioned. This defaults to `192.168.4.1:80` if not specified
* `--ssid <AP SSID>` (Optional)
- For specifying the SSID of the Wi-Fi AP to which the device is to connect after provisioning.
- If not provided, scanning is initiated and scan results, as seen by the device, are displayed, of which an SSID can be picked and the corresponding password specified.
* `--passphrase <AP Password>` (Optional)
- For specifying the password of the Wi-Fi AP to which the device is to connect after provisioning.
- Only used when corresponding SSID is provided using the `--ssid` option
* `--sec_ver <Security version number>`
- For specifying the version of protocomm endpoint security to use. Following 3 versions are supported:
* `0` for `protocomm_security0` - No security
* `1` for `protocomm_security1` - X25519 key exchange + Authentication using Proof of Possession (PoP) + AES-CTR encryption
* `2` for `protocomm_security2` - Secure Remote Password protocol (SRP6a) + AES-GCM encryption
* `--pop <Proof of possession string>` (Optional)
- For specifying optional Proof of Possession string to use for protocomm endpoint security version 1
- Ignored when other security versions are used
* `--sec2_username <SRP6a Username>` (Optional)
- For specifying optional username to use for protocomm endpoint security version 2
- Ignored when other security versions are used
* `--sec2_pwd <SRP6a Password>` (Optional)
- For specifying optional password to use for protocomm endpoint security version 2
- Ignored when other security versions are used
* `--sec2_gen_cred` (Optional)
- For generating the `SRP6a` credentials (salt and verifier) from the provided username and password for protocomm endpoint security version 2
- Ignored when other security versions are used
* `--sec2_salt_len <SRP6a Salt Length>` (Optional)
- For specifying the optional `SRP6a` salt length to be used for generating protocomm endpoint security version 2 credentials
- Ignored when other security versions are used and the ``--sec2_gen_cred` option is not set
* `--custom_data <some string>` (Optional)
An information string can be sent to the `custom-data` endpoint during provisioning using this argument.
@ -65,7 +88,7 @@ Usage of `esp-prov` assumes that the provisioning app has specific protocomm end
`esp_prov` is intended as a cross-platform tool, but currently BLE communication functionality is only available on Linux (via BlueZ and DBus)
For android, a provisioning tool along with source code is available [here](https://github.com/espressif/esp-idf-provisioning-android)
For Android, a provisioning tool along with source code is available [here](https://github.com/espressif/esp-idf-provisioning-android)
On macOS and Windows, running with `--transport ble` option falls back to console mode, ie. write data and target UUID are printed to STDOUT and read data is input through STDIN. Users are free to use their app of choice to connect to the BLE device, send the write data to the target characteristic and read from it.
@ -91,6 +114,6 @@ Run `pip install -r $IDF_PATH/tools/esp_prov/requirements_linux_extra.txt`
# EXAMPLE USAGE
Please refer to the README.md file with the `wifi_prov_mgr` example present under `$IDF_PATH/examples/provisioning/`.
Please refer to the `README.md` file with the `wifi_prov_mgr` example present under `$IDF_PATH/examples/provisioning/`.
This example uses specific options of the `esp_prov` tool and gives an overview of simple as well as advanced usage scenarios.

Wyświetl plik

@ -40,8 +40,10 @@ def on_except(err):
print(err)
def get_security(secver, pop='', verbose=False):
if secver == 1:
def get_security(secver, username, password, pop='', verbose=False):
if secver == 2:
return security.Security2(username, password, verbose)
elif secver == 1:
return security.Security1(pop, verbose)
elif secver == 0:
return security.Security0(verbose)
@ -331,15 +333,30 @@ if __name__ == '__main__':
'\t- 0 : No security',
'\t- 1 : X25519 key exchange + AES-CTR encryption',
'\t + Authentication using Proof of Possession (PoP)',
'\t- 2 : SRP6a + AES-GCM encryption',
'In case device side application uses IDF\'s provisioning manager, '
'the compatible security version is automatically determined from '
'capabilities retrieved via the version endpoint'))
parser.add_argument('--pop', dest='pop', type=str, default='',
parser.add_argument('--pop', dest='sec1_pop', type=str, default='',
help=desc_format(
'This specifies the Proof of possession (PoP) when security scheme 1 '
'is used'))
parser.add_argument('--sec2_username', dest='sec2_usr', type=str, default='',
help=desc_format(
'Username for security scheme 2 (SRP6a)'))
parser.add_argument('--sec2_pwd', dest='sec2_pwd', type=str, default='',
help=desc_format(
'Password for security scheme 2 (SRP6a)'))
parser.add_argument('--sec2_gen_cred', help='Generate salt and verifier for security scheme 2 (SRP6a)', action='store_true')
parser.add_argument('--sec2_salt_len', dest='sec2_salt_len', type=int, default=16,
help=desc_format(
'Salt length for security scheme 2 (SRP6a)'))
parser.add_argument('--ssid', dest='ssid', type=str, default='',
help=desc_format(
'This configures the device to use SSID of the Wi-Fi network to which '
@ -363,6 +380,14 @@ if __name__ == '__main__':
args = parser.parse_args()
if args.secver == 2 and args.sec2_gen_cred:
if not args.sec2_usr or not args.sec2_pwd:
print('---- Username/password cannot be empty for security scheme 2 (SRP6a) ----')
exit(1)
print('==== Salt-verifier for security scheme 2 (SRP6a) ====')
security.sec2_gen_salt_verifier(args.sec2_usr, args.sec2_pwd, args.sec2_salt_len)
exit(0)
obj_transport = get_transport(args.mode.lower(), args.name)
if obj_transport is None:
print('---- Failed to establish connection ----')
@ -381,14 +406,14 @@ if __name__ == '__main__':
print('Security scheme determined to be :', args.secver)
if (args.secver != 0) and not has_capability(obj_transport, 'no_pop'):
if len(args.pop) == 0:
if len(args.sec1_pop) == 0:
print('---- Proof of Possession argument not provided ----')
exit(2)
elif len(args.pop) != 0:
elif len(args.sec1_pop) != 0:
print('---- Proof of Possession will be ignored ----')
args.pop = ''
args.sec1_pop = ''
obj_security = get_security(args.secver, args.pop, args.verbose)
obj_security = get_security(args.secver, args.sec2_usr, args.sec2_pwd, args.sec1_pop, args.verbose)
if obj_security is None:
print('---- Invalid Security Version ----')
exit(2)

Wyświetl plik

@ -9,8 +9,11 @@ from importlib.abc import Loader
from typing import Any
def _load_source(name, path): # type: (str, str) -> Any
def _load_source(name: str, path: str) -> Any:
spec = importlib.util.spec_from_file_location(name, path)
if not spec:
return None
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
assert isinstance(spec.loader, Loader)
@ -24,6 +27,7 @@ idf_path = os.environ['IDF_PATH']
constants_pb2 = _load_source('constants_pb2', idf_path + '/components/protocomm/python/constants_pb2.py')
sec0_pb2 = _load_source('sec0_pb2', idf_path + '/components/protocomm/python/sec0_pb2.py')
sec1_pb2 = _load_source('sec1_pb2', idf_path + '/components/protocomm/python/sec1_pb2.py')
sec2_pb2 = _load_source('sec2_pb2', idf_path + '/components/protocomm/python/sec2_pb2.py')
session_pb2 = _load_source('session_pb2', idf_path + '/components/protocomm/python/session_pb2.py')
# wifi_provisioning component related python files generated from .proto files

Wyświetl plik

@ -1,17 +1,7 @@
# 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
#
from .security0 import * # noqa: F403, F401
from .security1 import * # noqa: F403, F401
from .security2 import * # noqa: F403, F401

Wyświetl plik

@ -0,0 +1,167 @@
# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
# APIs for interpreting and creating protobuf packets for
# protocomm endpoint with security type protocomm_security2
from typing import Any, Type
import proto
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from future.utils import tobytes
from .security import Security
from .srp6a import Srp6a, bytes_to_long, generate_salt_and_verifier, long_to_bytes
AES_KEY_LEN = 256 // 8
# Enum for state of protocomm_security1 FSM
class security_state:
REQUEST1 = 0
RESPONSE1_REQUEST2 = 1
RESPONSE2 = 2
FINISHED = 3
def sec2_gen_salt_verifier(username: str, password: str, salt_len: int) -> Any:
salt, verifier = generate_salt_and_verifier(username, password, len_s=salt_len)
salt_str = ', '.join([format(b, '#04x') for b in salt])
salt_c_arr = '\n '.join(salt_str[i: i + 96] for i in range(0, len(salt_str), 96))
print(f'static const char sec2_salt[] = {{\n {salt_c_arr}\n}};\n')
verifier_str = ', '.join([format(b, '#04x') for b in verifier])
verifier_c_arr = '\n '.join(verifier_str[i: i + 96] for i in range(0, len(verifier_str), 96))
print(f'static const char sec2_verifier[] = {{\n {verifier_c_arr}\n}};\n')
class Security2(Security):
def __init__(self, username: str, password: str, verbose: bool) -> None:
# Initialize state of the security2 FSM
self.session_state = security_state.REQUEST1
self.username = username
self.password = password
self.verbose = verbose
self.srp6a_ctx: Type[Srp6a]
self.cipher: Type[AESGCM]
self.client_pop_key = None
self.nonce = None
Security.__init__(self, self.security2_session)
def security2_session(self, response_data: bytes) -> Any:
# protocomm security2 FSM which interprets/forms
# protobuf packets according to present state of session
if (self.session_state == security_state.REQUEST1):
self.session_state = security_state.RESPONSE1_REQUEST2
return self.setup0_request()
if (self.session_state == security_state.RESPONSE1_REQUEST2):
self.session_state = security_state.RESPONSE2
self.setup0_response(response_data)
return self.setup1_request()
if (self.session_state == security_state.RESPONSE2):
self.session_state = security_state.FINISHED
self.setup1_response(response_data)
return None
print('Unexpected state')
return None
def _print_verbose(self, data: str) -> None:
if (self.verbose):
print(f'\x1b[32;20m++++ {data} ++++\x1b[0m')
def setup0_request(self) -> Any:
# Form SessionCmd0 request packet using client public key
setup_req = proto.session_pb2.SessionData()
setup_req.sec_ver = proto.session_pb2.SecScheme2
setup_req.sec2.msg = proto.sec2_pb2.S2Session_Command0
setup_req.sec2.sc0.client_username = tobytes(self.username)
self.srp6a_ctx = Srp6a(self.username, self.password)
if self.srp6a_ctx is None:
print('Failed to initialize SRP6a instance!')
exit(1)
client_pubkey = long_to_bytes(self.srp6a_ctx.A)
setup_req.sec2.sc0.client_pubkey = client_pubkey
self._print_verbose('Client Public Key:\t' + hex(bytes_to_long(client_pubkey)))
return setup_req.SerializeToString().decode('latin-1')
def setup0_response(self, response_data: bytes) -> None:
# Interpret SessionResp0 response packet
setup_resp = proto.session_pb2.SessionData()
setup_resp.ParseFromString(tobytes(response_data))
self._print_verbose('Security version:\t' + str(setup_resp.sec_ver))
if setup_resp.sec_ver != proto.session_pb2.SecScheme2:
print('Incorrect sec scheme')
exit(1)
# Device public key, random salt and password verifier
device_pubkey = setup_resp.sec2.sr0.device_pubkey
device_salt = setup_resp.sec2.sr0.device_salt
self._print_verbose('Device Public Key:\t' + hex(bytes_to_long(device_pubkey)))
self._print_verbose('Device Salt:\t' + hex(bytes_to_long(device_salt)))
self.client_pop_key = self.srp6a_ctx.process_challenge(device_salt, device_pubkey)
def setup1_request(self) -> Any:
# Form SessionCmd1 request packet using encrypted device public key
setup_req = proto.session_pb2.SessionData()
setup_req.sec_ver = proto.session_pb2.SecScheme2
setup_req.sec2.msg = proto.sec2_pb2.S2Session_Command1
# Encrypt device public key and attach to the request packet
self._print_verbose('Client Proof:\t' + hex(bytes_to_long(self.client_pop_key)))
setup_req.sec2.sc1.client_proof = self.client_pop_key
return setup_req.SerializeToString().decode('latin-1')
def setup1_response(self, response_data: bytes) -> Any:
# Interpret SessionResp1 response packet
setup_resp = proto.session_pb2.SessionData()
setup_resp.ParseFromString(tobytes(response_data))
# Ensure security scheme matches
if setup_resp.sec_ver == proto.session_pb2.SecScheme2:
# Read encrypyed device proof string
device_proof = setup_resp.sec2.sr1.device_proof
self._print_verbose('Device Proof:\t' + hex(bytes_to_long(device_proof)))
self.srp6a_ctx.verify_session(device_proof)
if not self.srp6a_ctx.authenticated():
print('Failed to verify device proof')
exit(1)
else:
print('Unsupported security protocol')
exit(1)
# Getting the shared secret
shared_secret = self.srp6a_ctx.get_session_key()
self._print_verbose('Shared Secret:\t' + hex(bytes_to_long(shared_secret)))
# Using the first 256 bits of a 512 bit key
session_key = shared_secret[:AES_KEY_LEN]
self._print_verbose('Session Key:\t' + hex(bytes_to_long(session_key)))
# 96-bit nonce
self.nonce = setup_resp.sec2.sr1.device_nonce
self._print_verbose('Nonce:\t' + hex(bytes_to_long(self.nonce)))
# Initialize the encryption engine with Shared Key and initialization vector
self.cipher = AESGCM(session_key)
if self.cipher is None:
print('Failed to initialize AES-GCM cryptographic engine!')
exit(1)
def encrypt_data(self, data: bytes) -> Any:
return self.cipher.encrypt(self.nonce, data, None)
def decrypt_data(self, data: bytes) -> Any:
return self.cipher.decrypt(self.nonce, data, None)

Wyświetl plik

@ -0,0 +1,308 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
# N A large safe prime (N = 2q+1, where q is prime) [All arithmetic is done modulo N]
# g A generator modulo N
# k Multiplier parameter (k = H(N, g) in SRP-6a, k = 3 for legacy SRP-6)
# s User's salt
# Iu Username
# p Cleartext Password
# H() One-way hash function
# ^ (Modular) Exponentiation
# u Random scrambling parameter
# a, b Secret ephemeral values
# A, B Public ephemeral values
# x Private key (derived from p and s)
# v Password verifier
import hashlib
import os
from typing import Any, Callable, Optional, Tuple
SHA1 = 0
SHA224 = 1
SHA256 = 2
SHA384 = 3
SHA512 = 4
NG_1024 = 0
NG_2048 = 1
NG_3072 = 2
NG_4096 = 3
NG_8192 = 4
_hash_map = {SHA1: hashlib.sha1,
SHA224: hashlib.sha224,
SHA256: hashlib.sha256,
SHA384: hashlib.sha384,
SHA512: hashlib.sha512}
_ng_const = (
# 1024-bit
('''\
EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496\
EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8E\
F4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA\
9AFD5138FE8376435B9FC61D2FC0EB06E3''',
'2'),
# 2048
('''\
AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4\
A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60\
95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF\
747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907\
8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861\
60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB\
FBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73''',
'2'),
# 3072
('''\
FFFFFFFFFFFFFFFFC90FDAA22168C2\
34C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E\
3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B5\
76625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE\
9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D3\
9A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED5290770\
96966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E77\
2C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF69558171839\
95497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A\
33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6\
E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA\
06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C77\
0988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2\
CAFFFFFFFFFFFFFFFF''',
'5'),
# 4096
('''\
FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08\
8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B\
302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9\
A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6\
49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8\
FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D\
670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C\
180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718\
3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D\
04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D\
B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226\
1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C\
BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC\
E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26\
99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB\
04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2\
233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127\
D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199\
FFFFFFFFFFFFFFFF''',
'5'),
# 8192
('''\
FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08\
8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B\
302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9\
A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6\
49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8\
FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D\
670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C\
180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718\
3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D\
04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D\
B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226\
1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C\
BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC\
E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26\
99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB\
04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2\
233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127\
D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492\
36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406\
AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918\
DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151\
2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03\
F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F\
BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA\
CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B\
B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632\
387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E\
6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA\
3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C\
5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9\
22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886\
2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6\
6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5\
0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268\
359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6\
FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71\
60C980DD98EDD3DFFFFFFFFFFFFFFFFF''',
'0x13')
)
def get_ng(ng_type: int) -> Tuple[int, int]:
n_hex, g_hex = _ng_const[ng_type]
return int(n_hex, 16), int(g_hex, 16)
def bytes_to_long(s: bytes) -> int:
return int.from_bytes(s, 'big')
def long_to_bytes(n: int) -> bytes:
if n == 0:
return b'\x00'
return n.to_bytes((n.bit_length() + 7) // 8, 'big')
def get_random(nbytes: int) -> int:
return bytes_to_long(os.urandom(nbytes))
def get_random_of_length(nbytes: int) -> int:
offset = (nbytes * 8) - 1
return get_random(nbytes) | (1 << offset)
def H(hash_class: Callable, *args: Any, **kwargs: Any) -> int:
width = kwargs.get('width', None)
h = hash_class()
for s in args:
if s is not None:
data = long_to_bytes(s) if isinstance(s, int) else s
if width is not None:
h.update(bytes(width - len(data)))
h.update(data)
return int(h.hexdigest(), 16)
def H_N_xor_g(hash_class: Callable, N: int, g: int) -> bytes:
bin_N = long_to_bytes(N)
bin_g = long_to_bytes(g)
padding = len(bin_N) - len(bin_g)
hN = hash_class(bin_N).digest()
hg = hash_class(b''.join([b'\0' * padding, bin_g])).digest()
return b''.join(long_to_bytes(hN[i] ^ hg[i]) for i in range(0, len(hN)))
def calculate_x(hash_class: Callable, s: Any, Iu: str, p: str) -> int:
_Iu = Iu.encode()
_p = p.encode()
return H(hash_class, s, H(hash_class, _Iu + b':' + _p))
def generate_salt_and_verifier(Iu: str, p: str, len_s: int, hash_alg: int = SHA512, ng_type: int = NG_3072) -> Tuple[bytes, bytes]:
hash_class = _hash_map[hash_alg]
N, g = get_ng(ng_type)
_s = long_to_bytes(get_random(len_s))
_v = long_to_bytes(pow(g, calculate_x(hash_class, _s, Iu, p), N))
return _s, _v
def calculate_M(hash_class: Callable, N: int, g: int, Iu: str, s: int, A: int, B: int, K: bytes) -> Any:
_Iu = Iu.encode()
h = hash_class()
h.update(H_N_xor_g(hash_class, N, g))
h.update(hash_class(_Iu).digest())
h.update(long_to_bytes(s))
h.update(long_to_bytes(A))
h.update(long_to_bytes(B))
h.update(K)
return h.digest()
def calculate_H_AMK(hash_class: Callable, A: int, M: bytes, K: bytes) -> Any:
h = hash_class()
h.update(long_to_bytes(A))
h.update(M)
h.update(K)
return h.digest()
class Srp6a (object):
def __init__(self, username: str, password: str, hash_alg: int = SHA512, ng_type: int = NG_3072):
hash_class = _hash_map[hash_alg]
N, g = get_ng(ng_type)
k = H(hash_class, N, g, width=len(long_to_bytes(N)))
self.Iu = username
self.p = password
self.a = get_random_of_length(32)
self.A = pow(g, self.a, N)
self.v: Optional[int] = None
self.K: Optional[bytes] = None
self.H_AMK = None
self._authenticated = False
self.hash_class = hash_class
self.N = N
self.g = g
self.k = k
def authenticated(self) -> bool:
return self._authenticated
def get_username(self) -> str:
return self.Iu
def get_ephemeral_secret(self) -> bytes:
return long_to_bytes(self.a)
def get_session_key(self) -> Any:
return self.K if self._authenticated else None
def start_authentication(self) -> Tuple[str, bytes]:
return (self.Iu, long_to_bytes(self.A))
# Returns M or None if SRP-6a safety check is violated
def process_challenge(self, bytes_s: bytes, bytes_B: bytes) -> Any:
s = bytes_to_long(bytes_s)
B = bytes_to_long(bytes_B)
N = self.N
g = self.g
k = self.k
hash_class = self.hash_class
# SRP-6a safety check
if (B % N) == 0:
return None
u = H(hash_class, self.A, B, width=len(long_to_bytes(N)))
if u == 0: # SRP-6a safety check
return None
x = calculate_x(hash_class, s, self.Iu, self.p)
v = pow(g, x, N)
S = pow((B - k * v), (self.a + u * x), N)
self.K = hash_class(long_to_bytes(S)).digest()
M = calculate_M(hash_class, N, g, self.Iu, s, self.A, B, self.K)
if not M:
return None
self.H_AMK = calculate_H_AMK(hash_class, self.A, M, self.K)
return M
def verify_session(self, host_HAMK: bytes) -> None:
if self.H_AMK == host_HAMK:
self._authenticated = True
class AuthenticationFailed (Exception):
pass

Wyświetl plik

@ -1,16 +1,5 @@
# 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
#
# Convenience functions for commonly used data type conversions
@ -22,7 +11,7 @@ from future.utils import tobytes
def str_to_hexstr(string):
# Form hexstr by appending ASCII codes (in hex) corresponding to
# each character in the input string
return binascii.hexlify(tobytes(string)).decode()
return binascii.hexlify(tobytes(string)).decode('latin-1')
def hexstr_to_str(hexstr):
@ -31,4 +20,4 @@ def hexstr_to_str(hexstr):
hexstr = '0' + hexstr
# Interpret consecutive pairs of hex characters as 8 bit ASCII codes
# and append characters corresponding to each code to form the string
return binascii.unhexlify(tobytes(hexstr)).decode()
return binascii.unhexlify(tobytes(hexstr)).decode('latin-1')