diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-07-16 15:45:08 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-07-16 15:45:08 +0300 |
commit | 393f6b682c1f67d8fb3f468a60e361d6f4e1b348 (patch) | |
tree | 479b724011f06b8156eab8cdbf63cdc1c36cd8b2 /src/ui | |
parent | d16ec2473b826790238b0f0404f037c3155fe19a (diff) |
Improved TOFU implementation
If a server sends a different certificate (checked by matching public key fingerprints), abort the connection at the TLS handshake stage.
A new error page is shown explaining the situation. A button is provided for conveniently opening Page Information, where trust can be updated.
The file format of "visited.txt" was updated, so it is now called "visited.2.txt". The new format includes server port numbers, and the fingerprints are calculated based on public keys.
IssueID #308
IssueID #309
IssueID #310
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/documentwidget.c | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 7e6c2ea4..4a4101b1 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -1135,6 +1135,16 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode | |||
1135 | useBanner = iFalse; /* valid data wasn't received from host */ | 1135 | useBanner = iFalse; /* valid data wasn't received from host */ |
1136 | appendFormat_String(src, "\n\n>%s\n", cstr_String(meta)); | 1136 | appendFormat_String(src, "\n\n>%s\n", cstr_String(meta)); |
1137 | break; | 1137 | break; |
1138 | /* fall through */ | ||
1139 | case tlsServerCertificateNotVerified_GmStatusCode: | ||
1140 | makeFooterButtons_DocumentWidget_( | ||
1141 | d, | ||
1142 | (iMenuItem[]){ { info_Icon " ${menu.pageinfo}", | ||
1143 | SDLK_i, | ||
1144 | KMOD_PRIMARY, | ||
1145 | "document.info" } }, | ||
1146 | 1); | ||
1147 | break; | ||
1138 | case failedToOpenFile_GmStatusCode: | 1148 | case failedToOpenFile_GmStatusCode: |
1139 | case certificateNotValid_GmStatusCode: | 1149 | case certificateNotValid_GmStatusCode: |
1140 | appendFormat_String(src, "\n\n%s", cstr_String(meta)); | 1150 | appendFormat_String(src, "\n\n%s", cstr_String(meta)); |
@@ -1143,10 +1153,6 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode | |||
1143 | iString *key = collectNew_String(); | 1153 | iString *key = collectNew_String(); |
1144 | toString_Sym(SDLK_s, KMOD_PRIMARY, key); | 1154 | toString_Sym(SDLK_s, KMOD_PRIMARY, key); |
1145 | appendFormat_String(src, "\n```\n%s\n```\n", cstr_String(meta)); | 1155 | appendFormat_String(src, "\n```\n%s\n```\n", cstr_String(meta)); |
1146 | // appendFormat_String(src, | ||
1147 | // cstr_Lang("error.unsupported.suggestsave"), | ||
1148 | // cstr_String(key), | ||
1149 | // saveToDownloads_Label); | ||
1150 | makeFooterButtons_DocumentWidget_( | 1156 | makeFooterButtons_DocumentWidget_( |
1151 | d, | 1157 | d, |
1152 | (iMenuItem[]){ { translateCStr_Lang(download_Icon " " saveToDownloads_Label), | 1158 | (iMenuItem[]){ { translateCStr_Lang(download_Icon " " saveToDownloads_Label), |
@@ -1565,7 +1571,8 @@ static void updateTrust_DocumentWidget_(iDocumentWidget *d, const iGmResponse *r | |||
1565 | } | 1571 | } |
1566 | setFlags_Widget(as_Widget(lock), disabled_WidgetFlag, iFalse); | 1572 | setFlags_Widget(as_Widget(lock), disabled_WidgetFlag, iFalse); |
1567 | const iBool isDarkMode = isDark_ColorTheme(colorTheme_App()); | 1573 | const iBool isDarkMode = isDark_ColorTheme(colorTheme_App()); |
1568 | if (~d->certFlags & domainVerified_GmCertFlag) { | 1574 | if (~d->certFlags & domainVerified_GmCertFlag || |
1575 | ~d->certFlags & trusted_GmCertFlag) { | ||
1569 | updateTextCStr_LabelWidget(lock, red_ColorEscape warning_Icon); | 1576 | updateTextCStr_LabelWidget(lock, red_ColorEscape warning_Icon); |
1570 | } | 1577 | } |
1571 | else if (d->certFlags & trusted_GmCertFlag) { | 1578 | else if (d->certFlags & trusted_GmCertFlag) { |
@@ -2592,8 +2599,11 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2592 | setFocus_Widget(NULL); | 2599 | setFocus_Widget(NULL); |
2593 | iArray *items = new_Array(sizeof(iMenuItem)); | 2600 | iArray *items = new_Array(sizeof(iMenuItem)); |
2594 | if (canTrust) { | 2601 | if (canTrust) { |
2595 | pushBack_Array( | 2602 | pushBack_Array(items, |
2596 | items, &(iMenuItem){ uiTextCaution_ColorEscape "${dlg.cert.trust}", 0, 0, "server.trustcert" }); | 2603 | &(iMenuItem){ uiTextCaution_ColorEscape "${dlg.cert.trust}", |
2604 | SDLK_u, | ||
2605 | KMOD_PRIMARY | KMOD_SHIFT, | ||
2606 | "server.trustcert" }); | ||
2597 | } | 2607 | } |
2598 | if (haveFingerprint) { | 2608 | if (haveFingerprint) { |
2599 | pushBack_Array(items, &(iMenuItem){ "${dlg.cert.fingerprint}", 0, 0, "server.copycert" }); | 2609 | pushBack_Array(items, &(iMenuItem){ "${dlg.cert.fingerprint}", 0, 0, "server.copycert" }); |
@@ -2627,11 +2637,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2627 | if (!isEmpty_Block(d->certFingerprint) && !isEmpty_Range(&host)) { | 2637 | if (!isEmpty_Block(d->certFingerprint) && !isEmpty_Range(&host)) { |
2628 | setTrusted_GmCerts(certs_App(), host, port, d->certFingerprint, &d->certExpiry); | 2638 | setTrusted_GmCerts(certs_App(), host, port, d->certFingerprint, &d->certExpiry); |
2629 | d->certFlags |= trusted_GmCertFlag; | 2639 | d->certFlags |= trusted_GmCertFlag; |
2630 | postCommand_Widget(w, "document.info"); | 2640 | postCommand_Widget(w, "navigate.reload"); |
2631 | updateTrust_DocumentWidget_(d, NULL); | ||
2632 | redoLayout_GmDocument(d->doc); | ||
2633 | invalidate_DocumentWidget_(d); | ||
2634 | refresh_Widget(d); | ||
2635 | } | 2641 | } |
2636 | return iTrue; | 2642 | return iTrue; |
2637 | } | 2643 | } |