Prepare to use SHA256 fingerprints of certs.

First let's make clear we're currently using SHA1 & untangle the tlscerts
API from fingerprint specific details.

Related-to: https://github.com/profanity-im/profanity/issues/2068
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
This commit is contained in:
Steffen Jaeckel
2025-11-04 17:09:54 +01:00
parent 7f5ae430af
commit 4dcaa839fa
6 changed files with 50 additions and 51 deletions

View File

@@ -291,12 +291,12 @@ cmd_tls_trust(ProfWin* window, const char* const command, gchar** args)
return TRUE; return TRUE;
} }
cafile_add(cert); cafile_add(cert);
if (tlscerts_exists(cert->fingerprint)) { if (tlscerts_exists(cert)) {
cons_show("Certificate %s already trusted.", cert->fingerprint); cons_show("Certificate %s already trusted.", cert->fingerprint_sha1);
tlscerts_free(cert); tlscerts_free(cert);
return TRUE; return TRUE;
} }
cons_show("Adding %s to trusted certificates.", cert->fingerprint); cons_show("Adding %s to trusted certificates.", cert->fingerprint_sha1);
tlscerts_add(cert); tlscerts_add(cert);
tlscerts_free(cert); tlscerts_free(cert);
return TRUE; return TRUE;

View File

@@ -61,7 +61,7 @@ void
cafile_add(const TLSCertificate* cert) cafile_add(const TLSCertificate* cert)
{ {
if (!cert->pem) { if (!cert->pem) {
log_error("[CAfile] can't store cert with fingerprint %s: PEM is empty", cert->fingerprint); log_error("[CAfile] can't store cert with fingerprint %s: PEM is empty", cert->fingerprint_sha1);
return; return;
} }
auto_gchar gchar* cafile = _cafile_name(); auto_gchar gchar* cafile = _cafile_name();
@@ -76,13 +76,13 @@ cafile_add(const TLSCertificate* cert)
log_error("[CAfile] could not read from %s: %s", cafile, PROF_GERROR_MESSAGE(glib_error)); log_error("[CAfile] could not read from %s: %s", cafile, PROF_GERROR_MESSAGE(glib_error));
return; return;
} }
if (strstr(contents, cert->fingerprint)) { if (strstr(contents, cert->fingerprint_sha1)) {
log_debug("[CAfile] fingerprint %s already stored", cert->fingerprint); log_debug("[CAfile] fingerprint %s already stored", cert->fingerprint_sha1);
return; return;
} }
} }
const char* header = "# Profanity CAfile\n# DO NOT EDIT - this file is automatically generated"; const char* header = "# Profanity CAfile\n# DO NOT EDIT - this file is automatically generated";
new_contents = g_strdup_printf("%s\n\n# %s\n%s", contents ? contents : header, cert->fingerprint, cert->pem); new_contents = g_strdup_printf("%s\n\n# %s\n%s", contents ? contents : header, cert->fingerprint_sha1, cert->pem);
if (!g_file_set_contents(cafile, new_contents, -1, &glib_error)) if (!g_file_set_contents(cafile, new_contents, -1, &glib_error))
log_error("[CAfile] could not write to %s: %s", cafile, PROF_GERROR_MESSAGE(glib_error)); log_error("[CAfile] could not write to %s: %s", cafile, PROF_GERROR_MESSAGE(glib_error));
} }

View File

@@ -90,18 +90,18 @@ tlscerts_init(void)
} }
void void
tlscerts_set_current(const char* const fp) tlscerts_set_current(const TLSCertificate* cert)
{ {
if (current_fp) { if (current_fp) {
free(current_fp); free(current_fp);
} }
current_fp = strdup(fp); current_fp = strdup(cert->fingerprint_sha1);
} }
char* gboolean
tlscerts_get_current(void) tlscerts_current_fingerprint_equals(const TLSCertificate* cert)
{ {
return current_fp; return g_strcmp0(current_fp, cert->fingerprint_sha1) == 0;
} }
void void
@@ -114,9 +114,9 @@ tlscerts_clear_current(void)
} }
gboolean gboolean
tlscerts_exists(const char* const fingerprint) tlscerts_exists(const TLSCertificate* cert)
{ {
return g_key_file_has_group(tlscerts, fingerprint); return g_key_file_has_group(tlscerts, cert->fingerprint_sha1);
} }
GList* GList*
@@ -147,14 +147,14 @@ tlscerts_list(void)
} }
TLSCertificate* TLSCertificate*
tlscerts_new(const char* const fingerprint, int version, const char* const serialnumber, const char* const subjectname, tlscerts_new(const char* fingerprint_sha1, int version, const char* serialnumber, const char* subjectname,
const char* const issuername, const char* const notbefore, const char* const notafter, const char* issuername, const char* notbefore, const char* notafter,
const char* const key_alg, const char* const signature_alg, const char* const pem) const char* key_alg, const char* signature_alg, const char* pem)
{ {
TLSCertificate* cert = calloc(1, sizeof(TLSCertificate)); TLSCertificate* cert = calloc(1, sizeof(TLSCertificate));
if (fingerprint) { if (fingerprint_sha1) {
cert->fingerprint = strdup(fingerprint); cert->fingerprint_sha1 = strdup(fingerprint_sha1);
} }
cert->version = version; cert->version = version;
if (serialnumber) { if (serialnumber) {
@@ -254,40 +254,40 @@ tlscerts_add(const TLSCertificate* cert)
return; return;
} }
if (!cert->fingerprint) { if (!cert->fingerprint_sha1) {
return; return;
} }
autocomplete_add(certs_ac, cert->fingerprint); autocomplete_add(certs_ac, cert->fingerprint_sha1);
g_key_file_set_integer(tlscerts, cert->fingerprint, "version", cert->version); g_key_file_set_integer(tlscerts, cert->fingerprint_sha1, "version", cert->version);
if (cert->serialnumber) { if (cert->serialnumber) {
g_key_file_set_string(tlscerts, cert->fingerprint, "serialnumber", cert->serialnumber); g_key_file_set_string(tlscerts, cert->fingerprint_sha1, "serialnumber", cert->serialnumber);
} }
if (cert->subjectname) { if (cert->subjectname) {
g_key_file_set_string(tlscerts, cert->fingerprint, "subjectname", cert->subjectname); g_key_file_set_string(tlscerts, cert->fingerprint_sha1, "subjectname", cert->subjectname);
} }
if (cert->issuername) { if (cert->issuername) {
g_key_file_set_string(tlscerts, cert->fingerprint, "issuername", cert->issuername); g_key_file_set_string(tlscerts, cert->fingerprint_sha1, "issuername", cert->issuername);
} }
if (cert->notbefore) { if (cert->notbefore) {
g_key_file_set_string(tlscerts, cert->fingerprint, "start", cert->notbefore); g_key_file_set_string(tlscerts, cert->fingerprint_sha1, "start", cert->notbefore);
} }
if (cert->notafter) { if (cert->notafter) {
g_key_file_set_string(tlscerts, cert->fingerprint, "end", cert->notafter); g_key_file_set_string(tlscerts, cert->fingerprint_sha1, "end", cert->notafter);
} }
if (cert->key_alg) { if (cert->key_alg) {
g_key_file_set_string(tlscerts, cert->fingerprint, "keyalg", cert->key_alg); g_key_file_set_string(tlscerts, cert->fingerprint_sha1, "keyalg", cert->key_alg);
} }
if (cert->signature_alg) { if (cert->signature_alg) {
g_key_file_set_string(tlscerts, cert->fingerprint, "signaturealg", cert->signature_alg); g_key_file_set_string(tlscerts, cert->fingerprint_sha1, "signaturealg", cert->signature_alg);
} }
_save_tlscerts(); _save_tlscerts();
} }
gboolean gboolean
tlscerts_revoke(const char* const fingerprint) tlscerts_revoke(const char* fingerprint)
{ {
gboolean result = g_key_file_remove_group(tlscerts, fingerprint, NULL); gboolean result = g_key_file_remove_group(tlscerts, fingerprint, NULL);
if (result) { if (result) {
@@ -300,7 +300,7 @@ tlscerts_revoke(const char* const fingerprint)
} }
TLSCertificate* TLSCertificate*
tlscerts_get_trusted(const char* const fingerprint) tlscerts_get_trusted(const char* fingerprint)
{ {
if (!g_key_file_has_group(tlscerts, fingerprint)) { if (!g_key_file_has_group(tlscerts, fingerprint)) {
return NULL; return NULL;
@@ -321,7 +321,7 @@ tlscerts_get_trusted(const char* const fingerprint)
} }
char* char*
tlscerts_complete(const char* const prefix, gboolean previous, void* context) tlscerts_complete(const char* prefix, gboolean previous, void* context)
{ {
return autocomplete_complete(certs_ac, prefix, TRUE, previous); return autocomplete_complete(certs_ac, prefix, TRUE, previous);
} }
@@ -360,7 +360,7 @@ tlscerts_free(TLSCertificate* cert)
free(cert->notbefore); free(cert->notbefore);
free(cert->notafter); free(cert->notafter);
free(cert->fingerprint); free(cert->fingerprint_sha1);
free(cert->key_alg); free(cert->key_alg);
free(cert->signature_alg); free(cert->signature_alg);

View File

@@ -62,7 +62,7 @@ typedef struct tls_cert_t
char* issuer_email; char* issuer_email;
char* notbefore; char* notbefore;
char* notafter; char* notafter;
char* fingerprint; char* fingerprint_sha1;
char* key_alg; char* key_alg;
char* signature_alg; char* signature_alg;
char* pem; char* pem;
@@ -70,29 +70,29 @@ typedef struct tls_cert_t
void tlscerts_init(void); void tlscerts_init(void);
TLSCertificate* tlscerts_new(const char* const fingerprint, int version, const char* const serialnumber, const char* const subjectname, TLSCertificate* tlscerts_new(const char* fingerprint_sha1, int version, const char* serialnumber, const char* subjectname,
const char* const issuername, const char* const notbefore, const char* const notafter, const char* issuername, const char* notbefore, const char* notafter,
const char* const key_alg, const char* const signature_alg, const char* const pem); const char* key_alg, const char* signature_alg, const char* pem);
void tlscerts_set_current(const char* const fp); void tlscerts_set_current(const TLSCertificate* cert);
char* tlscerts_get_current(void); gboolean tlscerts_current_fingerprint_equals(const TLSCertificate* cert);
void tlscerts_clear_current(void); void tlscerts_clear_current(void);
gboolean tlscerts_exists(const char* const fingerprint); gboolean tlscerts_exists(const TLSCertificate* cert);
void tlscerts_add(const TLSCertificate* cert); void tlscerts_add(const TLSCertificate* cert);
gboolean tlscerts_revoke(const char* const fingerprint); gboolean tlscerts_revoke(const char* fingerprint);
TLSCertificate* tlscerts_get_trusted(const char* const fingerprint); TLSCertificate* tlscerts_get_trusted(const char* fingerprint);
void tlscerts_free(TLSCertificate* cert); void tlscerts_free(TLSCertificate* cert);
GList* tlscerts_list(void); GList* tlscerts_list(void);
char* tlscerts_complete(const char* const prefix, gboolean previous, void* context); char* tlscerts_complete(const char* prefix, gboolean previous, void* context);
void tlscerts_reset_ac(void); void tlscerts_reset_ac(void);

View File

@@ -1157,14 +1157,13 @@ int
sv_ev_certfail(const char* const errormsg, const TLSCertificate* cert) sv_ev_certfail(const char* const errormsg, const TLSCertificate* cert)
{ {
// check profanity trusted certs // check profanity trusted certs
if (tlscerts_exists(cert->fingerprint)) { if (tlscerts_exists(cert)) {
cafile_add(cert); cafile_add(cert);
return 1; return 1;
} }
// check current cert // check current cert
char* current_fp = tlscerts_get_current(); if (tlscerts_current_fingerprint_equals(cert)) {
if (current_fp && g_strcmp0(current_fp, cert->fingerprint) == 0) {
return 1; return 1;
} }
@@ -1195,11 +1194,11 @@ sv_ev_certfail(const char* const errormsg, const TLSCertificate* cert)
if (g_strcmp0(cmd, "/tls allow") == 0) { if (g_strcmp0(cmd, "/tls allow") == 0) {
cons_show("Continuing with connection."); cons_show("Continuing with connection.");
tlscerts_set_current(cert->fingerprint); tlscerts_set_current(cert);
return 1; return 1;
} else if (g_strcmp0(cmd, "/tls always") == 0) { } else if (g_strcmp0(cmd, "/tls always") == 0) {
cons_show("Adding %s to trusted certificates.", cert->fingerprint); cons_show("Adding %s to trusted certificates.", cert->fingerprint_sha1);
if (!tlscerts_exists(cert->fingerprint)) { if (!tlscerts_exists(cert)) {
tlscerts_add(cert); tlscerts_add(cert);
cafile_add(cert); cafile_add(cert);
} }

View File

@@ -180,7 +180,7 @@ cons_show_tlscert_summary(const TLSCertificate* cert)
cons_show("Subject : %s", cert->subject_commonname); cons_show("Subject : %s", cert->subject_commonname);
cons_show("Issuer : %s", cert->issuer_commonname); cons_show("Issuer : %s", cert->issuer_commonname);
cons_show("Fingerprint : %s", cert->fingerprint); cons_show("Fingerprint : %s", cert->fingerprint_sha1);
} }
void void
@@ -260,7 +260,7 @@ cons_show_tlscert(const TLSCertificate* cert)
cons_show(" Start : %s", cert->notbefore); cons_show(" Start : %s", cert->notbefore);
cons_show(" End : %s", cert->notafter); cons_show(" End : %s", cert->notafter);
cons_show(" Fingerprint : %s", cert->fingerprint); cons_show(" Fingerprint : %s", cert->fingerprint_sha1);
} }
void void