diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-08-03 15:28:16 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-08-03 15:28:16 +0300 |
commit | 856fbf1bf25038997b3dd61fc8707370f085e6da (patch) | |
tree | 90c6526fc839184d24bdbd770a956c8568b2956b /src/gmrequest.c | |
parent | 922ad3220909b7314ca629949b44d7d3aa0336b2 (diff) |
Server certificate TOFU
Diffstat (limited to 'src/gmrequest.c')
-rw-r--r-- | src/gmrequest.c | 47 |
1 files changed, 38 insertions, 9 deletions
diff --git a/src/gmrequest.c b/src/gmrequest.c index 32b386b2..dc08d23b 100644 --- a/src/gmrequest.c +++ b/src/gmrequest.c | |||
@@ -1,5 +1,7 @@ | |||
1 | #include "gmrequest.h" | 1 | #include "gmrequest.h" |
2 | #include "gmutil.h" | 2 | #include "gmutil.h" |
3 | #include "gmcerts.h" | ||
4 | #include "app.h" | ||
3 | 5 | ||
4 | #include <the_Foundation/file.h> | 6 | #include <the_Foundation/file.h> |
5 | #include <the_Foundation/tlsrequest.h> | 7 | #include <the_Foundation/tlsrequest.h> |
@@ -20,7 +22,7 @@ struct Impl_GmRequest { | |||
20 | iObject object; | 22 | iObject object; |
21 | iMutex mutex; | 23 | iMutex mutex; |
22 | enum iGmRequestState state; | 24 | enum iGmRequestState state; |
23 | enum iGmRequestCertification certState; | 25 | int certFlags; |
24 | iString url; | 26 | iString url; |
25 | iTlsRequest *req; | 27 | iTlsRequest *req; |
26 | enum iGmStatusCode code; | 28 | enum iGmStatusCode code; |
@@ -38,7 +40,7 @@ iDefineAudienceGetter(GmRequest, finished) | |||
38 | void init_GmRequest(iGmRequest *d) { | 40 | void init_GmRequest(iGmRequest *d) { |
39 | init_Mutex(&d->mutex); | 41 | init_Mutex(&d->mutex); |
40 | d->state = initialized_GmRequestState; | 42 | d->state = initialized_GmRequestState; |
41 | d->certState = notApplicable_GmRequestCertification; | 43 | d->certFlags = 0; |
42 | init_String(&d->url); | 44 | init_String(&d->url); |
43 | d->req = NULL; | 45 | d->req = NULL; |
44 | d->code = none_GmStatusCode; | 46 | d->code = none_GmStatusCode; |
@@ -165,11 +167,25 @@ static void requestFinished_GmRequest_(iAnyObject *obj) { | |||
165 | } | 167 | } |
166 | SDL_RemoveTimer(d->timeoutId); | 168 | SDL_RemoveTimer(d->timeoutId); |
167 | d->timeoutId = 0; | 169 | d->timeoutId = 0; |
168 | d->state = finished_GmRequestState; | 170 | d->state = finished_GmRequestState; |
169 | #if 1 | 171 | d->certFlags = 0; |
170 | /* Check the server certificate. */ { | 172 | /* Check the server certificate. */ { |
171 | d->certState = invalid_GmRequestCertification; /* check trust */ | ||
172 | const iTlsCertificate *cert = serverCertificate_TlsRequest(d->req); | 173 | const iTlsCertificate *cert = serverCertificate_TlsRequest(d->req); |
174 | if (cert) { | ||
175 | iGmCerts * certDb = certs_App(); | ||
176 | const iRangecc domain = urlHost_String(&d->url); | ||
177 | d->certFlags |= available_GmRequestCertFlag; | ||
178 | if (!isExpired_TlsCertificate(cert)) { | ||
179 | d->certFlags |= timeVerified_GmRequestCertFlag; | ||
180 | } | ||
181 | if (verifyDomain_TlsCertificate(cert, domain)) { | ||
182 | d->certFlags |= domainVerified_GmRequestCertFlag; | ||
183 | } | ||
184 | if (checkTrust_GmCerts(certDb, domain, cert)) { | ||
185 | d->certFlags |= trusted_GmRequestCertFlag; | ||
186 | } | ||
187 | } | ||
188 | #if 0 | ||
173 | printf("Server certificate:\n%s\n", cstrLocal_String(pem_TlsCertificate(cert))); | 189 | printf("Server certificate:\n%s\n", cstrLocal_String(pem_TlsCertificate(cert))); |
174 | iBlock *sha = fingerprint_TlsCertificate(cert); | 190 | iBlock *sha = fingerprint_TlsCertificate(cert); |
175 | printf("Fingerprint: %s\n", | 191 | printf("Fingerprint: %s\n", |
@@ -188,8 +204,8 @@ static void requestFinished_GmRequest_(iAnyObject *obj) { | |||
188 | verifyDomain_TlsCertificate(cert, parts.host) ? "valid" : "not valid"); | 204 | verifyDomain_TlsCertificate(cert, parts.host) ? "valid" : "not valid"); |
189 | } | 205 | } |
190 | fflush(stdout); | 206 | fflush(stdout); |
191 | } | ||
192 | #endif | 207 | #endif |
208 | } | ||
193 | unlock_Mutex(&d->mutex); | 209 | unlock_Mutex(&d->mutex); |
194 | iNotifyAudience(d, finished, GmRequestFinished); | 210 | iNotifyAudience(d, finished, GmRequestFinished); |
195 | } | 211 | } |
@@ -211,7 +227,7 @@ void submit_GmRequest(iGmRequest *d) { | |||
211 | /* TODO: Check supported file types: images, audio */ | 227 | /* TODO: Check supported file types: images, audio */ |
212 | /* TODO: Detect text files based on contents? E.g., is the content valid UTF-8. */ | 228 | /* TODO: Detect text files based on contents? E.g., is the content valid UTF-8. */ |
213 | d->code = success_GmStatusCode; | 229 | d->code = success_GmStatusCode; |
214 | d->certState = notApplicable_GmRequestCertification; | 230 | d->certFlags = 0; |
215 | if (endsWithCase_String(path, ".gmi")) { | 231 | if (endsWithCase_String(path, ".gmi")) { |
216 | setCStr_String(&d->header, "text/gemini; charset=utf-8"); | 232 | setCStr_String(&d->header, "text/gemini; charset=utf-8"); |
217 | } | 233 | } |
@@ -231,6 +247,7 @@ void submit_GmRequest(iGmRequest *d) { | |||
231 | setCStr_String(&d->header, "application/octet-stream"); | 247 | setCStr_String(&d->header, "application/octet-stream"); |
232 | } | 248 | } |
233 | set_Block(&d->body, collect_Block(readAll_File(f))); | 249 | set_Block(&d->body, collect_Block(readAll_File(f))); |
250 | d->state = receivingBody_GmRequestState; | ||
234 | iNotifyAudience(d, updated, GmRequestUpdated); | 251 | iNotifyAudience(d, updated, GmRequestUpdated); |
235 | } | 252 | } |
236 | else { | 253 | else { |
@@ -238,14 +255,14 @@ void submit_GmRequest(iGmRequest *d) { | |||
238 | setCStr_String(&d->header, cstr_String(path)); | 255 | setCStr_String(&d->header, cstr_String(path)); |
239 | } | 256 | } |
240 | iRelease(f); | 257 | iRelease(f); |
258 | d->certFlags = 0; | ||
241 | d->state = finished_GmRequestState; | 259 | d->state = finished_GmRequestState; |
242 | d->certState = notApplicable_GmRequestCertification; | ||
243 | iNotifyAudience(d, finished, GmRequestFinished); | 260 | iNotifyAudience(d, finished, GmRequestFinished); |
244 | return; | 261 | return; |
245 | } | 262 | } |
246 | else if (equalCase_Rangecc(&url.protocol, "data")) { | 263 | else if (equalCase_Rangecc(&url.protocol, "data")) { |
247 | d->code = success_GmStatusCode; | 264 | d->code = success_GmStatusCode; |
248 | d->certState = notApplicable_GmRequestCertification; | 265 | d->certFlags = 0; |
249 | iString *src = collectNewCStr_String(url.protocol.start + 5); | 266 | iString *src = collectNewCStr_String(url.protocol.start + 5); |
250 | iRangecc header = { constBegin_String(src), constBegin_String(src) }; | 267 | iRangecc header = { constBegin_String(src), constBegin_String(src) }; |
251 | while (header.end < constEnd_String(src) && *header.end != ',') { | 268 | while (header.end < constEnd_String(src) && *header.end != ',') { |
@@ -269,6 +286,8 @@ void submit_GmRequest(iGmRequest *d) { | |||
269 | set_String(src, collect_String(urlDecode_String(src))); | 286 | set_String(src, collect_String(urlDecode_String(src))); |
270 | } | 287 | } |
271 | set_Block(&d->body, &src->chars); | 288 | set_Block(&d->body, &src->chars); |
289 | d->state = receivingBody_GmRequestState; | ||
290 | iNotifyAudience(d, updated, GmRequestUpdated); | ||
272 | d->state = finished_GmRequestState; | 291 | d->state = finished_GmRequestState; |
273 | iNotifyAudience(d, finished, GmRequestFinished); | 292 | iNotifyAudience(d, finished, GmRequestFinished); |
274 | return; | 293 | return; |
@@ -314,4 +333,14 @@ const iString *url_GmRequest(const iGmRequest *d) { | |||
314 | return &d->url; | 333 | return &d->url; |
315 | } | 334 | } |
316 | 335 | ||
336 | int certFlags_GmRequest(const iGmRequest *d) { | ||
337 | return d->certFlags; | ||
338 | } | ||
339 | |||
340 | iDate certExpirationDate_GmRequest(const iGmRequest *d) { | ||
341 | iDate expiry; | ||
342 | validUntil_TlsCertificate(serverCertificate_TlsRequest(d->req), &expiry); | ||
343 | return expiry; | ||
344 | } | ||
345 | |||
317 | iDefineClass(GmRequest) | 346 | iDefineClass(GmRequest) |