Skip to content

Commit 12fe019

Browse files
committed
Fix string matching of Windows Cert locations.
- Bug was how we used `strncpy()`. Any substring would look like a full string match. Ex: "Cu" would match "CurrentUser" because first 2 characters were same. Solution is to use our byte-cursor string matching functions. - Also, move to using byte-cursor functions instead of strchr and pointer arithmetic. These functions weren't available when this code was first written.
1 parent c8d96ec commit 12fe019

File tree

1 file changed

+55
-35
lines changed

1 file changed

+55
-35
lines changed

source/windows/windows_pki_utils.c

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,76 +21,96 @@
2121
#define CERT_HASH_STR_LEN 40
2222
#define CERT_HASH_LEN 20
2323

24+
/**
25+
* Split system cert path into exactly three segments like:
26+
* "CurrentUser\My\a11f8a9b5df5b98ba3508fbca575d09570e0d2c6"
27+
* -> ["CurrentUser", "My", "a11f8a9b5df5b98ba3508fbca575d09570e0d2c6"]
28+
*/
29+
static int s_split_system_cert_path(const char *cert_path, struct aws_byte_cursor out_splits[3]) {
30+
31+
struct aws_byte_cursor cert_path_cursor = aws_byte_cursor_from_c_str(cert_path);
32+
33+
struct aws_byte_cursor segment;
34+
AWS_ZERO_STRUCT(segment);
35+
36+
for (size_t i = 0; i < 3; ++i) {
37+
if (!aws_byte_cursor_next_split(&cert_path_cursor, '\\', &segment)) {
38+
AWS_LOGF_ERROR(
39+
AWS_LS_IO_PKI, "static: invalid certificate path '%s'. Expected additional '\\' separator.", cert_path);
40+
return aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
41+
}
42+
43+
out_splits[i] = segment;
44+
}
45+
46+
if (aws_byte_cursor_next_split(&cert_path_cursor, '\\', &segment)) {
47+
AWS_LOGF_ERROR(
48+
AWS_LS_IO_PKI, "static: invalid certificate path '%s'. Too many '\\' separators found.", cert_path);
49+
return aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
50+
}
51+
52+
return AWS_OP_SUCCESS;
53+
}
54+
2455
int aws_load_cert_from_system_cert_store(const char *cert_path, HCERTSTORE *cert_store, PCCERT_CONTEXT *certs) {
2556

2657
AWS_LOGF_INFO(AWS_LS_IO_PKI, "static: loading certificate at windows cert manager path '%s'.", cert_path);
27-
char *location_of_next_segment = strchr(cert_path, '\\');
2858

29-
if (!location_of_next_segment) {
30-
AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: invalid certificate path '%s'. Must use '\\' as separator.", cert_path);
31-
return aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
59+
struct aws_byte_cursor segments[3];
60+
if (s_split_system_cert_path(cert_path, segments)) {
61+
return AWS_OP_ERR;
3262
}
63+
const struct aws_byte_cursor store_location = segments[0];
64+
const struct aws_byte_cursor store_path_cursor = segments[1];
65+
const struct aws_byte_cursor cert_hash_cursor = segments[2];
3366

34-
size_t store_name_len = location_of_next_segment - cert_path;
3567
DWORD store_val = 0;
36-
37-
if (!strncmp(cert_path, "CurrentUser", store_name_len)) {
68+
if (aws_byte_cursor_eq_c_str_ignore_case(&store_location, "CurrentUser")) {
3869
store_val = CERT_SYSTEM_STORE_CURRENT_USER;
39-
} else if (!strncmp(cert_path, "LocalMachine", store_name_len)) {
70+
} else if (aws_byte_cursor_eq_c_str_ignore_case(&store_location, "LocalMachine")) {
4071
store_val = CERT_SYSTEM_STORE_LOCAL_MACHINE;
41-
} else if (!strncmp(cert_path, "CurrentService", store_name_len)) {
72+
} else if (aws_byte_cursor_eq_c_str_ignore_case(&store_location, "CurrentService")) {
4273
store_val = CERT_SYSTEM_STORE_CURRENT_SERVICE;
43-
} else if (!strncmp(cert_path, "Services", store_name_len)) {
74+
} else if (aws_byte_cursor_eq_c_str_ignore_case(&store_location, "Services")) {
4475
store_val = CERT_SYSTEM_STORE_SERVICES;
45-
} else if (!strncmp(cert_path, "Users", store_name_len)) {
76+
} else if (aws_byte_cursor_eq_c_str_ignore_case(&store_location, "Users")) {
4677
store_val = CERT_SYSTEM_STORE_USERS;
47-
} else if (!strncmp(cert_path, "CurrentUserGroupPolicy", store_name_len)) {
78+
} else if (aws_byte_cursor_eq_c_str_ignore_case(&store_location, "CurrentUserGroupPolicy")) {
4879
store_val = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
49-
} else if (!strncmp(cert_path, "LocalMachineGroupPolicy", store_name_len)) {
80+
} else if (aws_byte_cursor_eq_c_str_ignore_case(&store_location, "LocalMachineGroupPolicy")) {
5081
store_val = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
51-
} else if (!strncmp(cert_path, "LocalMachineEnterprise", store_name_len)) {
82+
} else if (aws_byte_cursor_eq_c_str_ignore_case(&store_location, "LocalMachineEnterprise")) {
5283
store_val = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
5384
} else {
5485
AWS_LOGF_ERROR(
5586
AWS_LS_IO_PKI,
56-
"static: invalid certificate path '%s'. System store location '%.*s' not recognized."
87+
"static: invalid certificate path '%s'. System store location '" PRInSTR "' not recognized."
5788
" Expected something like 'CurrentUser'.",
5889
cert_path,
59-
(int)store_name_len,
60-
cert_path);
90+
AWS_BYTE_CURSOR_PRI(store_location));
6191

6292
return aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
6393
}
6494

6595
AWS_LOGF_DEBUG(AWS_LS_IO_PKI, "static: determined registry value for lookup as %d.", (int)store_val);
66-
location_of_next_segment += 1;
67-
char *store_path_start = location_of_next_segment;
68-
location_of_next_segment = strchr(location_of_next_segment, '\\');
69-
70-
if (!location_of_next_segment) {
71-
AWS_LOGF_ERROR(
72-
AWS_LS_IO_PKI, "static: invalid certificate path '%s'. Expected additional '\\' separator.", cert_path);
73-
return aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
74-
}
7596

7697
/* The store_val value has to be only the path segment related to the physical store. Looking
7798
at the docs, 128 bytes should be plenty to store that segment.
7899
https://docs.microsoft.com/en-us/windows/desktop/SecCrypto/system-store-locations */
79100
char store_path[128] = {0};
80-
if (location_of_next_segment - store_path_start >= sizeof(store_path)) {
101+
if (store_path_cursor.len >= sizeof(store_path)) {
81102
AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: invalid certificate path '%s'. Store name is too long.", cert_path);
82103
return aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
83104
}
84-
memcpy(store_path, store_path_start, location_of_next_segment - store_path_start);
105+
memcpy(store_path, store_path_cursor.ptr, store_path_cursor.len);
85106

86-
location_of_next_segment += 1;
87-
if (strlen(location_of_next_segment) != CERT_HASH_STR_LEN) {
107+
if (cert_hash_cursor.len != CERT_HASH_STR_LEN) {
88108
AWS_LOGF_ERROR(
89109
AWS_LS_IO_PKI,
90-
"static: invalid certificate path '%s'. '%s' should have been"
110+
"static: invalid certificate path '%s'. '" PRInSTR "' should have been"
91111
" 40 bytes of hex encoded data",
92112
cert_path,
93-
location_of_next_segment);
113+
AWS_BYTE_CURSOR_PRI(cert_hash_cursor));
94114
return aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
95115
}
96116

@@ -113,7 +133,7 @@ int aws_load_cert_from_system_cert_store(const char *cert_path, HCERTSTORE *cert
113133
};
114134

115135
if (!CryptStringToBinaryA(
116-
location_of_next_segment,
136+
(LPCSTR)cert_hash_cursor.ptr, /* this is null-terminated, it's the last segment of c-str */
117137
CERT_HASH_STR_LEN,
118138
CRYPT_STRING_HEX,
119139
cert_hash.pbData,
@@ -122,9 +142,9 @@ int aws_load_cert_from_system_cert_store(const char *cert_path, HCERTSTORE *cert
122142
NULL)) {
123143
AWS_LOGF_ERROR(
124144
AWS_LS_IO_PKI,
125-
"static: invalid certificate path '%s'. '%s' should have been a hex encoded string",
145+
"static: invalid certificate path '%s'. '" PRInSTR "' should have been a hex encoded string",
126146
cert_path,
127-
location_of_next_segment);
147+
AWS_BYTE_CURSOR_PRI(cert_hash_cursor));
128148
aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
129149
goto on_error;
130150
}

0 commit comments

Comments
 (0)