Skip to content

Commit d0de84f

Browse files
authored
Merge branch 'main' into codex/check-msg_len-and-block_size-for-overflow
2 parents 1eea010 + 85b0c93 commit d0de84f

4 files changed

Lines changed: 81 additions & 11 deletions

File tree

hmac.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ namespace hmac {
4848
ctx.finish(digest);
4949
return std::string((const char*)digest, hmac_hash::SHA512::DIGEST_SIZE);
5050
}
51-
default: break;
51+
default:
52+
throw std::invalid_argument("Unsupported hash type");
5253
};
53-
return std::string();
5454
}
5555

5656
std::vector<uint8_t> get_hash(const void* data, size_t length, TypeHash type) {
@@ -79,7 +79,8 @@ namespace hmac {
7979
ctx.finish(digest.data());
8080
return digest;
8181
}
82-
default: return {};
82+
default:
83+
throw std::invalid_argument("Unsupported hash type");
8384
}
8485
}
8586

@@ -155,7 +156,7 @@ namespace hmac {
155156
block_size = hmac_hash::SHA512::SHA384_512_BLOCK_SIZE;
156157
break;
157158
default:
158-
return std::string();
159+
throw std::invalid_argument("Unsupported hash type");
159160
};
160161

161162
std::string key = key_input;

hmac.mqh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ namespace hmac {
5454
string to_hex(const string& str, bool is_upper = false) {
5555
uchar bytes[];
5656
StringToCharArray(str, bytes, 0, -1, CP_UTF8);
57+
int len = ArraySize(bytes);
58+
if (len > 0 && bytes[len - 1] == '\0') len -= 1;
59+
ArrayResize(bytes, len);
5760
return to_hex(bytes, is_upper);
5861
}
5962

hmac_utils.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "hmac_utils.hpp"
22
#include <ctime>
3+
#include <cerrno>
34
#include <stdexcept>
45
#include <limits>
56

@@ -20,8 +21,9 @@ namespace hmac {
2021
if (interval_sec <= 0) {
2122
throw std::invalid_argument("interval_sec must be positive");
2223
}
24+
errno = 0;
2325
std::time_t now = std::time(nullptr);
24-
if (now == static_cast<std::time_t>(-1)) {
26+
if (now == static_cast<std::time_t>(-1) && errno != 0) {
2527
throw std::runtime_error("std::time failed");
2628
}
2729
std::time_t rounded = (now / interval_sec) * interval_sec;
@@ -32,8 +34,9 @@ namespace hmac {
3234
if (interval_sec <= 0) {
3335
throw std::invalid_argument("interval_sec must be positive");
3436
}
37+
errno = 0;
3538
std::time_t now = std::time(nullptr);
36-
if (now == static_cast<std::time_t>(-1)) {
39+
if (now == static_cast<std::time_t>(-1) && errno != 0) {
3740
throw std::runtime_error("std::time failed");
3841
}
3942
std::time_t rounded = (now / interval_sec) * interval_sec;
@@ -51,8 +54,9 @@ namespace hmac {
5154
if (interval_sec <= 0) {
5255
throw std::invalid_argument("interval_sec must be positive");
5356
}
57+
errno = 0;
5458
std::time_t now = std::time(nullptr);
55-
if (now == static_cast<std::time_t>(-1)) {
59+
if (now == static_cast<std::time_t>(-1) && errno != 0) {
5660
throw std::runtime_error("std::time failed");
5761
}
5862
std::time_t rounded = (now / interval_sec) * interval_sec;
@@ -64,8 +68,9 @@ namespace hmac {
6468
if (interval_sec <= 0) {
6569
throw std::invalid_argument("interval_sec must be positive");
6670
}
71+
errno = 0;
6772
std::time_t now = std::time(nullptr);
68-
if (now == static_cast<std::time_t>(-1)) {
73+
if (now == static_cast<std::time_t>(-1) && errno != 0) {
6974
throw std::runtime_error("std::time failed");
7075
}
7176
std::time_t rounded = (now / interval_sec) * interval_sec;
@@ -144,8 +149,9 @@ namespace hmac {
144149
if (digits < 1 || digits > 9) {
145150
throw std::invalid_argument("TOTP: digits must be in range [1, 9]");
146151
}
152+
errno = 0;
147153
std::time_t now = std::time(nullptr);
148-
if (now == static_cast<std::time_t>(-1)) {
154+
if (now == static_cast<std::time_t>(-1) && errno != 0) {
149155
throw std::runtime_error("std::time failed");
150156
}
151157
uint64_t timestamp = static_cast<uint64_t>(now);
@@ -192,8 +198,9 @@ namespace hmac {
192198
if (digits < 1 || digits > 9) {
193199
throw std::invalid_argument("TOTP: digits must be in range [1, 9]");
194200
}
201+
errno = 0;
195202
std::time_t now = std::time(nullptr);
196-
if (now == static_cast<std::time_t>(-1)) {
203+
if (now == static_cast<std::time_t>(-1) && errno != 0) {
197204
throw std::runtime_error("std::time failed");
198205
}
199206
uint64_t timestamp = static_cast<uint64_t>(now);

test_all.cpp

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
#include <stdexcept>
44
#include <vector>
55
#include <limits>
6+
#include <cerrno>
67

78
#include "hmac.hpp"
89
#include "hmac_utils.hpp"
910

1011
static std::time_t mock_time_value = 0;
12+
static int mock_errno_value = 0;
1113
extern "C" std::time_t time(std::time_t* t) {
1214
if (t) *t = mock_time_value;
15+
errno = mock_errno_value;
1316
return mock_time_value;
1417
}
1518

@@ -45,6 +48,17 @@ TEST(HashTest, SHA512LargeInput) {
4548
"596d71e02b4eca81f668215d3e9b9e5a143a9c3d8d1981608e0811b20e290961ec2a7e7ecd0e275366cf10aa5f7ab1e052b868c5fa57b6d2bd6e75477b2ecea7");
4649
}
4750

51+
TEST(HashTest, InvalidTypeThrowsString) {
52+
auto invalid = static_cast<hmac::TypeHash>(999);
53+
EXPECT_THROW(hmac::get_hash("grape", invalid), std::invalid_argument);
54+
}
55+
56+
TEST(HashTest, InvalidTypeThrowsBuffer) {
57+
auto invalid = static_cast<hmac::TypeHash>(999);
58+
const char data[] = "grape";
59+
EXPECT_THROW(hmac::get_hash(data, sizeof(data) - 1, invalid), std::invalid_argument);
60+
}
61+
4862
TEST(UtilsTest, ToHex) {
4963
EXPECT_EQ(hmac::to_hex("012345"), "303132333435");
5064
}
@@ -99,7 +113,14 @@ TEST(HMACTest, MsgLenOverflowThrows) {
99113
size_t huge_len = std::numeric_limits<size_t>::max() -
100114
hmac_hash::SHA256::SHA224_256_BLOCK_SIZE + 1;
101115
EXPECT_THROW(hmac::get_hmac(key, sizeof(key) - 1, msg, huge_len,
102-
hmac::TypeHash::SHA256), std::overflow_error);
116+
hmac::TypeHash::SHA256), std::overflow_error);
117+
}
118+
119+
TEST(HMACTest, InvalidTypeThrowsString) {
120+
const std::string key = "key";
121+
const std::string msg = "abc";
122+
auto invalid = static_cast<hmac::TypeHash>(999);
123+
EXPECT_THROW(hmac::get_hmac(key, msg, invalid), std::invalid_argument);
103124
}
104125

105126
TEST(TOTPTest, AtTime) {
@@ -166,6 +187,44 @@ TEST(TokenBoundaryFingerprintTest, MinTime) {
166187
EXPECT_TRUE(hmac::is_token_valid(token_next, key, fingerprint, interval));
167188
}
168189

190+
TEST(TimeErrorTest, MinusOneNoErrno) {
191+
const std::string key = "12345";
192+
mock_time_value = static_cast<std::time_t>(-1);
193+
mock_errno_value = 0;
194+
std::string token;
195+
EXPECT_NO_THROW(token = hmac::generate_time_token(key));
196+
EXPECT_EQ(token, hmac::get_hmac(key, "0", hmac::TypeHash::SHA256));
197+
mock_time_value = 0;
198+
mock_errno_value = 0;
199+
}
200+
201+
TEST(TimeErrorTest, MinusOneWithErrno) {
202+
const std::string key = "12345";
203+
mock_time_value = static_cast<std::time_t>(-1);
204+
mock_errno_value = EINVAL;
205+
EXPECT_THROW(hmac::generate_time_token(key), std::runtime_error);
206+
mock_errno_value = 0;
207+
mock_time_value = 0;
208+
}
209+
210+
TEST(TotpTimeErrorTest, MinusOneNoErrno) {
211+
const std::string key = "12345";
212+
mock_time_value = static_cast<std::time_t>(-1);
213+
mock_errno_value = 0;
214+
EXPECT_NO_THROW(hmac::get_totp_code(key));
215+
mock_time_value = 0;
216+
mock_errno_value = 0;
217+
}
218+
219+
TEST(TotpTimeErrorTest, MinusOneWithErrno) {
220+
const std::string key = "12345";
221+
mock_time_value = static_cast<std::time_t>(-1);
222+
mock_errno_value = EINVAL;
223+
EXPECT_THROW(hmac::get_totp_code(key), std::runtime_error);
224+
mock_errno_value = 0;
225+
mock_time_value = 0;
226+
}
227+
169228
int main(int argc, char **argv) {
170229
::testing::InitGoogleTest(&argc, argv);
171230
return RUN_ALL_TESTS();

0 commit comments

Comments
 (0)