Skip to content

Commit a6b2377

Browse files
authored
Merge pull request #2 from basmeerman/feature/native-state-machine-tests
Fix CI: cppcheck suppressions and optional signing
2 parents d793944 + c99ea27 commit a6b2377

File tree

3 files changed

+35
-21
lines changed

3 files changed

+35
-21
lines changed

.github/workflows/pio-build.yaml

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -78,43 +78,40 @@ jobs:
7878
python -m pip install --upgrade pip
7979
pip install --upgrade platformio
8080
- name: Build normal version
81+
run: |
82+
PLATFORMIO_BUILD_FLAGS='-DVERSION=\"v${{ steps.version.outputs.version }}\" -DDBG=0' pio run -d SmartEVSE-3/
83+
mkdir -p ./SmartEVSE-3/distribution
84+
- name: Sign normal version
85+
if: ${{ secrets.SECRET_RSA_KEY != '' }}
8186
env:
8287
super_secret: ${{ secrets.SECRET_RSA_KEY }}
8388
run: |
84-
PLATFORMIO_BUILD_FLAGS='-DVERSION=\"v${{ steps.version.outputs.version }}\" -DDBG=0' pio run -d SmartEVSE-3/
85-
# Create a temporary file
8689
secret_file=$(mktemp)
87-
# Write the secret to the temporary file, because passing it as command line argument might reveal it for users using ps -a
8890
echo "$super_secret" > "$secret_file"
89-
# Create signature file
9091
openssl dgst -sign "$secret_file" -keyform PEM -sha256 -out firmware.sign -binary ./SmartEVSE-3/.pio/build/release/firmware.bin
91-
# throw it all in one file
9292
cat firmware.sign ./SmartEVSE-3/.pio/build/release/firmware.bin > ./SmartEVSE-3/.pio/build/release/firmware.signed.bin
93-
94-
# save .bin files to directory because v4 upload-artifact@v4 can no longer add files to an existing artifact; so much for efficiency :-(
95-
mkdir ./SmartEVSE-3/distribution
96-
mv ./SmartEVSE-3/.pio/build/release/*.bin ./SmartEVSE-3/distribution
97-
98-
# Remove the temporary file
9993
rm -f "$secret_file"
94+
- name: Collect normal build artifacts
95+
run: mv ./SmartEVSE-3/.pio/build/release/*.bin ./SmartEVSE-3/distribution
10096
- name: Build debug version
97+
run: |
98+
PLATFORMIO_BUILD_FLAGS='-DVERSION=\"v${{ steps.version.outputs.version }}\" -DDBG=1' pio run -d SmartEVSE-3/
99+
- name: Sign debug version
100+
if: ${{ secrets.SECRET_RSA_KEY != '' }}
101101
env:
102102
super_secret: ${{ secrets.SECRET_RSA_KEY }}
103103
run: |
104-
PLATFORMIO_BUILD_FLAGS='-DVERSION=\"v${{ steps.version.outputs.version }}\" -DDBG=1' pio run -d SmartEVSE-3/
105-
# Create a temporary file
106104
secret_file=$(mktemp)
107-
# Write the secret to the temporary file, because passing it as command line argument might reveal it for users using ps -a
108105
echo "$super_secret" > "$secret_file"
109-
# Create signature file
110106
openssl dgst -sign "$secret_file" -keyform PEM -sha256 -out firmware.sign -binary ./SmartEVSE-3/.pio/build/release/firmware.bin
111-
# throw it all in one file
112107
cat firmware.sign ./SmartEVSE-3/.pio/build/release/firmware.bin > ./SmartEVSE-3/.pio/build/release/firmware.signed.bin
113-
# Remove the temporary file
114108
rm -f "$secret_file"
109+
- name: Collect debug build artifacts
110+
run: |
115111
mv ./SmartEVSE-3/.pio/build/release/firmware.bin ./SmartEVSE-3/distribution/firmware.debug.bin
116-
mv ./SmartEVSE-3/.pio/build/release/firmware.signed.bin ./SmartEVSE-3/distribution/firmware.debug.signed.bin
117-
# prevent the .bin files are gathered in .pio directory in the dists-zip file:
112+
if [ -f ./SmartEVSE-3/.pio/build/release/firmware.signed.bin ]; then
113+
mv ./SmartEVSE-3/.pio/build/release/firmware.signed.bin ./SmartEVSE-3/distribution/firmware.debug.signed.bin
114+
fi
118115
cp -a ./SmartEVSE-3/HowToFlash.txt ./SmartEVSE-3/distribution
119116
120117
# Combined upload for all artifacts using v4

SECURITY.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ SmartEVSE is an internet-connected device that controls mains electricity. Secur
2121
- Denial of service that could leave contactors in an unsafe state
2222
- Information disclosure of WiFi credentials or RFID card data
2323

24+
## Security Design Choices
25+
26+
### Shared Default TLS Certificate
27+
28+
The repository includes a self-signed EC private key (`SmartEVSE-3/data/key.pem`) and certificate (`SmartEVSE-3/data/cert.pem`) used for the device's built-in HTTPS web server. This is an intentional design choice: every SmartEVSE ships with the same default keypair so that HTTPS works out of the box without requiring a per-device provisioning step.
29+
30+
**Implications:**
31+
32+
- The private key is public knowledge. HTTPS provides encryption in transit but does not authenticate the device — an attacker on the local network could impersonate a SmartEVSE endpoint.
33+
- All devices share the same certificate, so compromising one does not increase risk to others (there is no unique secret to protect).
34+
- This is a common tradeoff in embedded devices where there is no certificate authority infrastructure or user-facing provisioning flow.
35+
36+
Users who require stronger TLS authentication should replace the default keypair with a device-specific certificate.
37+
2438
## Supported Versions
2539

2640
| Version | Supported |

SmartEVSE-3/src/evse_state_machine.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ static void record_pilot(evse_ctx_t *ctx, bool connected) {
6262
}
6363

6464
// ---- Initialization ----
65+
// cppcheck-suppress constParameterPointer
6566
void evse_init(evse_ctx_t *ctx, evse_hal_t *hal) {
6667
memset(ctx, 0, sizeof(evse_ctx_t));
6768

@@ -166,6 +167,7 @@ void evse_init(evse_ctx_t *ctx, evse_hal_t *hal) {
166167

167168
// ---- Phase switching helper ----
168169
// Faithful to Force_Single_Phase_Charging() in main.cpp:681-696
170+
// cppcheck-suppress constParameterPointer
169171
uint8_t evse_force_single_phase(evse_ctx_t *ctx) {
170172
switch (ctx->EnableC2) {
171173
case NOT_PRESENT: return 0; // 3P
@@ -446,10 +448,10 @@ void evse_calc_balanced_current(evse_ctx_t *ctx, int mod) {
446448
int32_t TotalCurrent = 0;
447449
int32_t ActiveMax = 0;
448450
int32_t Baseload, Baseload_EV;
449-
int32_t Idifference;
451+
int32_t Idifference; // cppcheck-suppress variableScope
450452
int32_t IsumImport = 0;
451453
bool LimitedByMaxSumMains = false;
452-
char CurrentSet[NR_EVSES] = {0};
454+
char CurrentSet[NR_EVSES] = {0}; // cppcheck-suppress variableScope
453455

454456
// ---- Phase 1: ChargeCurrent (lines 1158-1179) ----
455457
if (ctx->BalancedState[0] == STATE_C && ctx->MaxCurrent > ctx->MaxCapacity && ctx->MaxCapacity)
@@ -601,6 +603,7 @@ void evse_calc_balanced_current(evse_ctx_t *ctx, int mod) {
601603

602604
// Solar shortage: 3P->1P switching (lines 1337-1370)
603605
if (ctx->Mode == MODE_SOLAR) {
606+
// cppcheck-suppress knownConditionTrueFalse
604607
if (ActiveEVSE && IsumImport > 0 &&
605608
(ctx->Isum > (int32_t)((ActiveEVSE * ctx->MinCurrent * ctx->Nr_Of_Phases_Charging
606609
- ctx->StartCurrent) * 10) ||

0 commit comments

Comments
 (0)