diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-08-03 18:27:45 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-08-03 18:27:45 +0300 |
commit | c5f7132d637f0186433cccb4da7b9283a4dd5d9a (patch) | |
tree | c5e912733437e307fb894366cc8bf648776a53ce | |
parent | 8f62f251ee5e49447c0950719ba6629bc1a23257 (diff) |
GmCerts: Thread safety; fixed notifications
Must update the status before notifying.
-rw-r--r-- | src/gmcerts.c | 18 | ||||
-rw-r--r-- | src/gmrequest.c | 40 |
2 files changed, 36 insertions, 22 deletions
diff --git a/src/gmcerts.c b/src/gmcerts.c index 0aa084a4..11e9ce2c 100644 --- a/src/gmcerts.c +++ b/src/gmcerts.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include "gmcerts.h" | 1 | #include "gmcerts.h" |
2 | 2 | ||
3 | #include <the_Foundation/file.h> | 3 | #include <the_Foundation/file.h> |
4 | #include <the_Foundation/mutex.h> | ||
4 | #include <the_Foundation/path.h> | 5 | #include <the_Foundation/path.h> |
5 | #include <the_Foundation/regexp.h> | 6 | #include <the_Foundation/regexp.h> |
6 | #include <the_Foundation/stringhash.h> | 7 | #include <the_Foundation/stringhash.h> |
@@ -32,6 +33,7 @@ iDefineClass(TrustEntry) | |||
32 | /*-----------------------------------------------------------------------------------------------*/ | 33 | /*-----------------------------------------------------------------------------------------------*/ |
33 | 34 | ||
34 | struct Impl_GmCerts { | 35 | struct Impl_GmCerts { |
36 | iMutex mtx; | ||
35 | iString saveDir; | 37 | iString saveDir; |
36 | iStringHash *trusted; | 38 | iStringHash *trusted; |
37 | }; | 39 | }; |
@@ -87,14 +89,18 @@ static void load_GmCerts_(iGmCerts *d) { | |||
87 | } | 89 | } |
88 | 90 | ||
89 | void init_GmCerts(iGmCerts *d, const char *saveDir) { | 91 | void init_GmCerts(iGmCerts *d, const char *saveDir) { |
92 | init_Mutex(&d->mtx); | ||
90 | initCStr_String(&d->saveDir, saveDir); | 93 | initCStr_String(&d->saveDir, saveDir); |
91 | d->trusted = new_StringHash(); | 94 | d->trusted = new_StringHash(); |
92 | load_GmCerts_(d); | 95 | load_GmCerts_(d); |
93 | } | 96 | } |
94 | 97 | ||
95 | void deinit_GmCerts(iGmCerts *d) { | 98 | void deinit_GmCerts(iGmCerts *d) { |
96 | iRelease(d->trusted); | 99 | iGuardMutex(&d->mtx, { |
97 | deinit_String(&d->saveDir); | 100 | iRelease(d->trusted); |
101 | deinit_String(&d->saveDir); | ||
102 | }); | ||
103 | deinit_Mutex(&d->mtx); | ||
98 | } | 104 | } |
99 | 105 | ||
100 | iBool checkTrust_GmCerts(iGmCerts *d, iRangecc domain, const iTlsCertificate *cert) { | 106 | iBool checkTrust_GmCerts(iGmCerts *d, iRangecc domain, const iTlsCertificate *cert) { |
@@ -112,6 +118,7 @@ iBool checkTrust_GmCerts(iGmCerts *d, iRangecc domain, const iTlsCertificate *ce | |||
112 | iDate until; | 118 | iDate until; |
113 | validUntil_TlsCertificate(cert, &until); | 119 | validUntil_TlsCertificate(cert, &until); |
114 | iBlock *fingerprint = collect_Block(fingerprint_TlsCertificate(cert)); | 120 | iBlock *fingerprint = collect_Block(fingerprint_TlsCertificate(cert)); |
121 | lock_Mutex(&d->mtx); | ||
115 | iTrustEntry *trust = value_StringHash(d->trusted, key); | 122 | iTrustEntry *trust = value_StringHash(d->trusted, key); |
116 | if (trust) { | 123 | if (trust) { |
117 | /* We already have it, check if it matches the one we trust for this domain (if it's | 124 | /* We already have it, check if it matches the one we trust for this domain (if it's |
@@ -120,7 +127,9 @@ iBool checkTrust_GmCerts(iGmCerts *d, iRangecc domain, const iTlsCertificate *ce | |||
120 | initCurrent_Time(&now); | 127 | initCurrent_Time(&now); |
121 | if (secondsSince_Time(&trust->validUntil, &now) > 0) { | 128 | if (secondsSince_Time(&trust->validUntil, &now) > 0) { |
122 | /* Trusted cert is still valid. */ | 129 | /* Trusted cert is still valid. */ |
123 | return cmp_Block(fingerprint, &trust->fingerprint) == 0; | 130 | const iBool isTrusted = cmp_Block(fingerprint, &trust->fingerprint) == 0; |
131 | unlock_Mutex(&d->mtx); | ||
132 | return isTrusted; | ||
124 | } | 133 | } |
125 | /* Update the trusted cert. */ | 134 | /* Update the trusted cert. */ |
126 | init_Time(&trust->validUntil, &until); | 135 | init_Time(&trust->validUntil, &until); |
@@ -130,5 +139,6 @@ iBool checkTrust_GmCerts(iGmCerts *d, iRangecc domain, const iTlsCertificate *ce | |||
130 | insert_StringHash(d->trusted, key, iClob(new_TrustEntry(fingerprint, &until))); | 139 | insert_StringHash(d->trusted, key, iClob(new_TrustEntry(fingerprint, &until))); |
131 | } | 140 | } |
132 | save_GmCerts_(d); | 141 | save_GmCerts_(d); |
142 | unlock_Mutex(&d->mtx); | ||
133 | return iTrue; | 143 | return iTrue; |
134 | } | 144 | } |
diff --git a/src/gmrequest.c b/src/gmrequest.c index dc08d23b..c0697f49 100644 --- a/src/gmrequest.c +++ b/src/gmrequest.c | |||
@@ -98,6 +98,25 @@ static void restartTimeout_GmRequest_(iGmRequest *d) { | |||
98 | d->timeoutId = SDL_AddTimer(BODY_TIMEOUT, timedOutWhileReceivingBody_GmRequest_, d); | 98 | d->timeoutId = SDL_AddTimer(BODY_TIMEOUT, timedOutWhileReceivingBody_GmRequest_, d); |
99 | } | 99 | } |
100 | 100 | ||
101 | static void checkServerCertificate_GmRequest_(iGmRequest *d) { | ||
102 | const iTlsCertificate *cert = serverCertificate_TlsRequest(d->req); | ||
103 | d->certFlags = 0; | ||
104 | if (cert) { | ||
105 | iGmCerts * certDb = certs_App(); | ||
106 | const iRangecc domain = urlHost_String(&d->url); | ||
107 | d->certFlags |= available_GmRequestCertFlag; | ||
108 | if (!isExpired_TlsCertificate(cert)) { | ||
109 | d->certFlags |= timeVerified_GmRequestCertFlag; | ||
110 | } | ||
111 | if (verifyDomain_TlsCertificate(cert, domain)) { | ||
112 | d->certFlags |= domainVerified_GmRequestCertFlag; | ||
113 | } | ||
114 | if (checkTrust_GmCerts(certDb, domain, cert)) { | ||
115 | d->certFlags |= trusted_GmRequestCertFlag; | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | |||
101 | static void readIncoming_GmRequest_(iAnyObject *obj) { | 120 | static void readIncoming_GmRequest_(iAnyObject *obj) { |
102 | iGmRequest *d = (iGmRequest *) obj; | 121 | iGmRequest *d = (iGmRequest *) obj; |
103 | iBool notifyUpdate = iFalse; | 122 | iBool notifyUpdate = iFalse; |
@@ -136,6 +155,7 @@ static void readIncoming_GmRequest_(iAnyObject *obj) { | |||
136 | } | 155 | } |
137 | d->code = code; | 156 | d->code = code; |
138 | d->state = receivingBody_GmRequestState; | 157 | d->state = receivingBody_GmRequestState; |
158 | checkServerCertificate_GmRequest_(d); | ||
139 | notifyUpdate = iTrue; | 159 | notifyUpdate = iTrue; |
140 | /* Start a timeout for the remainder of the response, in case the connection | 160 | /* Start a timeout for the remainder of the response, in case the connection |
141 | remains open. */ | 161 | remains open. */ |
@@ -168,23 +188,7 @@ static void requestFinished_GmRequest_(iAnyObject *obj) { | |||
168 | SDL_RemoveTimer(d->timeoutId); | 188 | SDL_RemoveTimer(d->timeoutId); |
169 | d->timeoutId = 0; | 189 | d->timeoutId = 0; |
170 | d->state = finished_GmRequestState; | 190 | d->state = finished_GmRequestState; |
171 | d->certFlags = 0; | 191 | checkServerCertificate_GmRequest_(d); |
172 | /* Check the server certificate. */ { | ||
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 | 192 | #if 0 |
189 | printf("Server certificate:\n%s\n", cstrLocal_String(pem_TlsCertificate(cert))); | 193 | printf("Server certificate:\n%s\n", cstrLocal_String(pem_TlsCertificate(cert))); |
190 | iBlock *sha = fingerprint_TlsCertificate(cert); | 194 | iBlock *sha = fingerprint_TlsCertificate(cert); |
@@ -205,7 +209,6 @@ static void requestFinished_GmRequest_(iAnyObject *obj) { | |||
205 | } | 209 | } |
206 | fflush(stdout); | 210 | fflush(stdout); |
207 | #endif | 211 | #endif |
208 | } | ||
209 | unlock_Mutex(&d->mutex); | 212 | unlock_Mutex(&d->mutex); |
210 | iNotifyAudience(d, finished, GmRequestFinished); | 213 | iNotifyAudience(d, finished, GmRequestFinished); |
211 | } | 214 | } |
@@ -218,6 +221,7 @@ void submit_GmRequest(iGmRequest *d) { | |||
218 | d->code = none_GmStatusCode; | 221 | d->code = none_GmStatusCode; |
219 | clear_String(&d->header); | 222 | clear_String(&d->header); |
220 | clear_Block(&d->body); | 223 | clear_Block(&d->body); |
224 | d->certFlags = 0; | ||
221 | iUrl url; | 225 | iUrl url; |
222 | init_Url(&url, &d->url); | 226 | init_Url(&url, &d->url); |
223 | if (equalCase_Rangecc(&url.protocol, "file")) { | 227 | if (equalCase_Rangecc(&url.protocol, "file")) { |