Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
0.15.2 (TBD)
============

Changes:
- Use SHA256 fingerprints for TLS certificate trust instead of deprecated SHA1
Improves security of certificate pinning and TOFU (Trust On First Use)
- Update TLS certificate UI messages to indicate SHA256 checksums
- Add comprehensive TLS security documentation to README

0.15.1 (2025-08-22)
===================

Expand Down
88 changes: 88 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,94 @@ Feel free to follow us on [twitter](https://twitter.com/profanityim), join our [
## Installation
Our [user guide](https://profanity-im.github.io/userguide.html) contains an [install](https://profanity-im.github.io/guide/latest/install.html) section and a section for [building](https://profanity-im.github.io/guide/latest/build.html) from source yourself.

## Security Features

### TLS Certificate Verification with SHA256 Fingerprints

Profanity implements robust TLS certificate verification using **SHA256 fingerprints** for enhanced security. This addresses the deprecation of SHA1 and provides stronger protection against man-in-the-middle attacks.

#### Key Features

- **SHA256 Fingerprint Support**: Certificate fingerprints now use SHA256 hashing algorithm instead of deprecated SHA1
- **Certificate Pinning**: Pin specific certificates by their SHA256 fingerprint to prevent MITM attacks
- **Trust On First Use (TOFU)**: Securely establish trust with servers on first connection
- **Manual Trust Management**: Full control over which certificates to trust
- **Backward Compatibility**: Automatically falls back to SHA1 for older libstrophe versions

#### Why SHA256?

SHA256 provides significant security improvements over SHA1:
- **Collision Resistant**: SHA1 has known collision vulnerabilities; SHA256 is cryptographically secure
- **Industry Standard**: SHA256 is the current standard for certificate fingerprinting (NIST SP 800-131A)
- **Future-Proof**: Provides long-term security for certificate verification
- **Compliance**: Meets modern security requirements and best practices

#### TLS Commands

```
/tls cert Display current server's certificate with SHA256 fingerprint
/tls cert <fingerprint> Show details of a trusted certificate by SHA256 fingerprint
/tls trust Add current certificate to manually trusted certificates
/tls trusted List all manually trusted certificates with SHA256 checksums
/tls revoke <fingerprint> Remove a certificate from trusted list by SHA256 fingerprint
/tls allow Allow connection with current certificate (one-time)
/tls always Always allow connections with current certificate
/tls deny Abort connection with untrusted certificate
/tls certpath Show the trusted certificate path
/tls certpath set <path> Specify filesystem path containing trusted certificates
/tls certpath clear Clear the trusted certificate path
/tls certpath default Use default system certificate path
```

#### Usage Example

When connecting to a server with an untrusted certificate, Profanity will display:

```
TLS certificate verification failed: certificate not trusted
Certificate:
Subject:
Common name : xmpp.example.com
Issuer:
Common name : xmpp.example.com
Fingerprint (SHA256): A1:B2:C3:D4:E5:F6:07:08:09:0A:1B:2C:3D:4E:5F:60:71:82:93:A4:B5:C6:D7:E8:F9:0A:1B:2C:3D:4E:5F:60

Use '/tls allow' to accept this certificate.
Use '/tls always' to accept this certificate permanently.
Use '/tls deny' to reject this certificate.
```

To permanently trust this certificate:
```
/tls always
```

To view all trusted certificates:
```
/tls trusted
```

#### Implementation Details

This feature is implemented across multiple components:

- **Core**: `src/xmpp/connection.c` - Uses `XMPP_CERT_FINGERPRINT_SHA256` from libstrophe
- **Storage**: `src/config/tlscerts.c` - Stores trusted certificates with fingerprints
- **UI**: `src/ui/console.c` - Displays SHA256 fingerprints to users
- **Commands**: `src/command/cmd_funcs.c` - Implements TLS management commands

#### Requirements

- libstrophe >= 0.12.3 (provides SHA256 fingerprint support)
- OpenSSL or GnuTLS (for TLS support)

#### Security Considerations

- **Self-Signed Certificates**: SHA256 fingerprints allow secure use of self-signed certificates
- **Certificate Changes**: Users are alerted when a server's certificate changes
- **Persistent Trust**: Trusted certificates are stored locally for future connections
- **Manual Verification**: Users should verify fingerprints through a trusted channel before trusting

## Donations
We would highly appreciate it if you support us via [GitHub Sponsors](https://github.com/sponsors/jubalh/). Especially if you make feature requests or need help using Profanity.
Sponsoring enables us to spend time on Profanity.
Expand Down
10 changes: 5 additions & 5 deletions src/command/cmd_defs.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,16 +199,16 @@ static const struct cmd_t command_defs[] = {
"/tls certpath clear",
"/tls certpath default")
CMD_DESC(
"Handle TLS certificates. ")
"Handle TLS certificates. Certificate fingerprints use SHA256 checksums for enhanced security.")
CMD_ARGS(
{ "allow", "Allow connection to continue with TLS certificate." },
{ "always", "Always allow connections with TLS certificate." },
{ "deny", "Abort connection." },
{ "cert", "Show the current TLS certificate." },
{ "cert <fingerprint>", "Show details of trusted certificate." },
{ "cert", "Show the current TLS certificate with SHA256 fingerprint." },
{ "cert <fingerprint>", "Show details of trusted certificate by its SHA256 fingerprint." },
{ "trust", "Add the current TLS certificate to manually trusted certificates." },
{ "trusted", "List summary of manually trusted certificates (with '/tls always' or '/tls trust')." },
{ "revoke <fingerprint>", "Remove a manually trusted certificate." },
{ "trusted", "List summary of manually trusted certificates with SHA256 checksums (with '/tls always' or '/tls trust')." },
{ "revoke <fingerprint>", "Remove a manually trusted certificate by its SHA256 fingerprint." },
{ "certpath", "Show the trusted certificate path." },
{ "certpath set <path>", "Specify filesystem path containing trusted certificates." },
{ "certpath clear", "Clear the trusted certificate path." },
Expand Down
8 changes: 4 additions & 4 deletions src/command/cmd_funcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,11 @@ cmd_tls_trust(ProfWin* window, const char* const command, gchar** args)
}
cafile_add(cert);
if (tlscerts_exists(cert->fingerprint)) {
cons_show("Certificate %s already trusted.", cert->fingerprint);
cons_show("Certificate with SHA256 fingerprint %s already trusted.", cert->fingerprint);
tlscerts_free(cert);
return TRUE;
}
cons_show("Adding %s to trusted certificates.", cert->fingerprint);
cons_show("Adding certificate with SHA256 fingerprint %s to trusted certificates.", cert->fingerprint);
tlscerts_add(cert);
tlscerts_free(cert);
return TRUE;
Expand Down Expand Up @@ -332,9 +332,9 @@ cmd_tls_revoke(ProfWin* window, const char* const command, gchar** args)
} else {
gboolean res = tlscerts_revoke(args[1]);
if (res) {
cons_show("Trusted certificate revoked: %s", args[1]);
cons_show("Trusted certificate with SHA256 fingerprint revoked: %s", args[1]);
} else {
cons_show("Could not find certificate: %s", args[1]);
cons_show("Could not find certificate with SHA256 fingerprint: %s", args[1]);
}
}
return TRUE;
Expand Down
8 changes: 4 additions & 4 deletions src/ui/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,9 @@ cons_show_tlscert_summary(const TLSCertificate* cert)
return;
}

cons_show("Subject : %s", cert->subject_commonname);
cons_show("Issuer : %s", cert->issuer_commonname);
cons_show("Fingerprint : %s", cert->fingerprint);
cons_show("Subject : %s", cert->subject_commonname);
cons_show("Issuer : %s", cert->issuer_commonname);
cons_show("Fingerprint (SHA256): %s", cert->fingerprint);
}

void
Expand Down Expand Up @@ -260,7 +260,7 @@ cons_show_tlscert(const TLSCertificate* cert)
cons_show(" Start : %s", cert->notbefore);
cons_show(" End : %s", cert->notafter);

cons_show(" Fingerprint : %s", cert->fingerprint);
cons_show(" Fingerprint (SHA256): %s", cert->fingerprint);
}

void
Expand Down
11 changes: 10 additions & 1 deletion src/xmpp/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -1084,8 +1084,17 @@ _xmppcert_to_profcert(const xmpp_tlscert_t* xmpptlscert)
{
int version = (int)strtol(
xmpp_tlscert_get_string(xmpptlscert, XMPP_CERT_VERSION), NULL, 10);

// Use SHA256 fingerprint for better security (SHA1 is deprecated)
const char* fingerprint = xmpp_tlscert_get_string(xmpptlscert, XMPP_CERT_FINGERPRINT_SHA256);

// Fallback to SHA1 if SHA256 is not available (for older libstrophe versions)
if (!fingerprint) {
fingerprint = xmpp_tlscert_get_string(xmpptlscert, XMPP_CERT_FINGERPRINT_SHA1);
}

return tlscerts_new(
xmpp_tlscert_get_string(xmpptlscert, XMPP_CERT_FINGERPRINT_SHA1),
fingerprint,
version,
xmpp_tlscert_get_string(xmpptlscert, XMPP_CERT_SERIALNUMBER),
xmpp_tlscert_get_string(xmpptlscert, XMPP_CERT_SUBJECT),
Expand Down