summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars-Dominik Braun <lars@6xq.net>2011-11-11 14:45:21 +0100
committerLars-Dominik Braun <lars@6xq.net>2011-11-11 15:24:50 +0100
commita0e4f1e0f5989505f4aab10d64194b635f9af53c (patch)
tree6a7fe01f25d632b8fe40859af96ab96a3576022b
parentfb1b9c541346b3cfc80305ef12ee87ced70d5037 (diff)
downloadpianobar-a0e4f1e0f5989505f4aab10d64194b635f9af53c.tar.gz
pianobar-a0e4f1e0f5989505f4aab10d64194b635f9af53c.tar.bz2
pianobar-a0e4f1e0f5989505f4aab10d64194b635f9af53c.zip
waitress: Fingerprint check
Reduces memory usage, protects against 0wned CA's and avoids ca-bundle confusion. Closes #175
-rw-r--r--contrib/pianobar.15
-rw-r--r--src/libwaitress/waitress.c40
-rw-r--r--src/libwaitress/waitress.h4
-rw-r--r--src/main.c17
-rw-r--r--src/settings.c18
-rw-r--r--src/settings.h2
6 files changed, 32 insertions, 54 deletions
diff --git a/contrib/pianobar.1 b/contrib/pianobar.1
index dbff073..c5d3347 100644
--- a/contrib/pianobar.1
+++ b/contrib/pianobar.1
@@ -282,9 +282,8 @@ sorts by name from a to z, quickmix_01_name_za by type (quickmix at the
bottom) and name from z to a.
.TP
-.B tls_ca_path = /etc/ssl/certs/ca-certificates.crt
-File that contains the root certificate (and possibly intermediate
-certificates) of Pandora’s CA.
+.B tls_fingerprint = D9980BA2CC0F97BB03822C6211EAEA4A06EEF427
+Hex-encoded SHA1 fingerprint of Pandora’s TLS certificate.
.TP
.B user = your@user.name
diff --git a/src/libwaitress/waitress.c b/src/libwaitress/waitress.c
index 8bb519a..7082ffd 100644
--- a/src/libwaitress/waitress.c
+++ b/src/libwaitress/waitress.c
@@ -53,21 +53,11 @@ typedef struct {
size_t pos;
} WaitressFetchBufCbBuffer_t;
-WaitressReturn_t WaitressInit (WaitressHandle_t *waith, const char *caPath) {
+void WaitressInit (WaitressHandle_t *waith) {
assert (waith != NULL);
memset (waith, 0, sizeof (*waith));
waith->timeout = 30000;
- if (caPath != NULL) {
- gnutls_certificate_allocate_credentials (&waith->tlsCred);
- if (gnutls_certificate_set_x509_trust_file (waith->tlsCred, caPath,
- GNUTLS_X509_FMT_PEM) <= 0) {
- return WAITRESS_RET_TLS_TRUSTFILE_ERR;
- }
- waith->tlsInitialized = true;
- }
-
- return WAITRESS_RET_OK;
}
void WaitressFree (WaitressHandle_t *waith) {
@@ -75,9 +65,6 @@ void WaitressFree (WaitressHandle_t *waith) {
free (waith->url.url);
free (waith->proxy.url);
- if (waith->tlsInitialized) {
- gnutls_certificate_free_credentials (waith->tlsCred);
- }
memset (waith, 0, sizeof (*waith));
}
@@ -709,22 +696,10 @@ static int WaitressTlsVerify (gnutls_session_t session) {
waith = gnutls_session_get_ptr (session);
assert (waith != NULL);
- if (gnutls_certificate_verify_peers2 (session, &status) != GNUTLS_E_SUCCESS) {
- return GNUTLS_E_CERTIFICATE_ERROR;
- }
-
- /* don't accept invalid certs */
- if (status & (GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND |
- GNUTLS_CERT_REVOKED | GNUTLS_CERT_EXPIRED |
- GNUTLS_CERT_NOT_ACTIVATED)) {
- return GNUTLS_E_CERTIFICATE_ERROR;
- }
-
if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) {
return GNUTLS_E_CERTIFICATE_ERROR;
}
- /* check hostname */
if ((certList = gnutls_certificate_get_peers (session,
&certListSize)) == NULL) {
return GNUTLS_E_CERTIFICATE_ERROR;
@@ -739,7 +714,14 @@ static int WaitressTlsVerify (gnutls_session_t session) {
return GNUTLS_E_CERTIFICATE_ERROR;
}
- if (gnutls_x509_crt_check_hostname (cert, waith->url.host) == 0) {
+ char fingerprint[20];
+ size_t fingerprintSize = sizeof (fingerprint);
+ if (gnutls_x509_crt_get_fingerprint (cert, GNUTLS_DIG_SHA1, fingerprint,
+ &fingerprintSize) != 0) {
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ if (memcmp (fingerprint, waith->tlsFingerprint, sizeof (fingerprint)) != 0) {
return GNUTLS_E_CERTIFICATE_ERROR;
}
@@ -1036,8 +1018,6 @@ WaitressReturn_t WaitressFetchCall (WaitressHandle_t *waith) {
waith->request.write = WaitressOrdinaryWrite;
if (waith->url.tls) {
- assert (waith->tlsInitialized);
-
waith->request.read = WaitressGnutlsRead;
waith->request.write = WaitressGnutlsWrite;
gnutls_init (&waith->request.tlsSession, GNUTLS_CLIENT);
@@ -1046,6 +1026,7 @@ WaitressReturn_t WaitressFetchCall (WaitressHandle_t *waith) {
"PERFORMANCE", &err) != GNUTLS_E_SUCCESS) {
return WAITRESS_RET_ERR;
}
+ gnutls_certificate_allocate_credentials (&waith->tlsCred);
if (gnutls_credentials_set (waith->request.tlsSession,
GNUTLS_CRD_CERTIFICATE,
waith->tlsCred) != GNUTLS_E_SUCCESS) {
@@ -1083,6 +1064,7 @@ WaitressReturn_t WaitressFetchCall (WaitressHandle_t *waith) {
if (waith->url.tls) {
gnutls_bye (waith->request.tlsSession, GNUTLS_SHUT_RDWR);
gnutls_deinit (waith->request.tlsSession);
+ gnutls_certificate_free_credentials (waith->tlsCred);
}
close (waith->request.sockfd);
diff --git a/src/libwaitress/waitress.h b/src/libwaitress/waitress.h
index e1cf303..7e4401a 100644
--- a/src/libwaitress/waitress.h
+++ b/src/libwaitress/waitress.h
@@ -92,8 +92,8 @@ typedef struct {
void *data;
WaitressCbReturn_t (*callback) (void *, size_t, void *);
int timeout;
+ const char *tlsFingerprint;
gnutls_certificate_credentials_t tlsCred;
- bool tlsInitialized;
/* per-request data */
struct {
@@ -110,7 +110,7 @@ typedef struct {
} request;
} WaitressHandle_t;
-WaitressReturn_t WaitressInit (WaitressHandle_t *, const char *);
+void WaitressInit (WaitressHandle_t *);
void WaitressFree (WaitressHandle_t *);
bool WaitressSetProxy (WaitressHandle_t *, const char *);
char *WaitressUrlEncode (const char *);
diff --git a/src/main.c b/src/main.c
index e14a88a..afa75da 100644
--- a/src/main.c
+++ b/src/main.c
@@ -192,7 +192,7 @@ static void BarMainStartPlayback (BarApp_t *app, pthread_t *playerThread) {
/* setup player */
memset (&app->player, 0, sizeof (app->player));
- WaitressInit (&app->player.waith, NULL);
+ WaitressInit (&app->player.waith);
WaitressSetUrl (&app->player.waith, app->playlist->audioUrl);
/* set up global proxy, player is NULLed on songfinish */
@@ -328,7 +328,6 @@ int main (int argc, char **argv) {
static BarApp_t app;
/* terminal attributes _before_ we started messing around with ~ECHO */
struct termios termOrig;
- WaitressReturn_t wRet;
memset (&app, 0, sizeof (app));
@@ -355,19 +354,10 @@ int main (int argc, char **argv) {
app.settings.keys[BAR_KS_HELP]);
}
- if ((wRet = WaitressInit (&app.waith, app.settings.tlsCaPath)) != WAITRESS_RET_OK) {
- if (wRet == WAITRESS_RET_TLS_TRUSTFILE_ERR) {
- BarUiMsg (&app.settings, MSG_ERR, "Can't load root certificates. "
- "Please check the tls_ca_path setting in your config file.\n");
- } else {
- BarUiMsg (&app.settings, MSG_ERR, "Can't initialize HTTP library: "
- "%s\n", WaitressErrorToStr (wRet));
- }
- goto die;
- }
-
+ WaitressInit (&app.waith);
app.waith.url.host = strdup (PIANO_RPC_HOST);
app.waith.url.tls = true;
+ app.waith.tlsFingerprint = app.settings.tlsFingerprint;
/* init fds */
FD_ZERO(&app.input.set);
@@ -388,7 +378,6 @@ int main (int argc, char **argv) {
BarMainLoop (&app);
-die:
if (app.input.fds[1] != -1) {
close (app.input.fds[1]);
}
diff --git a/src/settings.c b/src/settings.c
index f29fcfa..ee332cc 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -93,7 +93,6 @@ void BarSettingsDestroy (BarSettings_t *settings) {
free (settings->npStationFormat);
free (settings->listSongFormat);
free (settings->fifo);
- free (settings->tlsCaPath);
for (size_t i = 0; i < MSG_COUNT; i++) {
free (settings->msgFormat[i].prefix);
free (settings->msgFormat[i].postfix);
@@ -132,7 +131,9 @@ void BarSettingsRead (BarSettings_t *settings) {
settings->listSongFormat = strdup ("%i) %a - %t%r");
settings->fifo = malloc (PATH_MAX * sizeof (*settings->fifo));
BarGetXdgConfigDir (PACKAGE "/ctl", settings->fifo, PATH_MAX);
- settings->tlsCaPath = strdup ("/etc/ssl/certs/ca-certificates.crt");
+ memcpy (settings->tlsFingerprint, "\xD9\x98\x0B\xA2\xCC\x0F\x97\xBB"
+ "\x03\x82\x2C\x62\x11\xEA\xEA\x4A\x06\xEE\xF4\x27",
+ sizeof (settings->tlsFingerprint));
settings->msgFormat[MSG_NONE].prefix = NULL;
settings->msgFormat[MSG_NONE].postfix = NULL;
@@ -241,9 +242,16 @@ void BarSettingsRead (BarSettings_t *settings) {
} else if (streq ("fifo", key)) {
free (settings->fifo);
settings->fifo = strdup (val);
- } else if (streq ("tls_ca_path", key)) {
- free (settings->tlsCaPath);
- settings->tlsCaPath = strdup (val);
+ } else if (streq ("tls_fingerprint", key)) {
+ /* expects 40 byte hex-encoded sha1 */
+ if (strlen (val) == 40) {
+ for (size_t i = 0; i < 20; i++) {
+ char hex[3];
+ memcpy (hex, &val[i*2], 2);
+ hex[2] = '\0';
+ settings->tlsFingerprint[i] = strtol (hex, NULL, 16);
+ }
+ }
} else if (strncmp (formatMsgPrefix, key,
strlen (formatMsgPrefix)) == 0) {
static const char *mapping[] = {"none", "info", "nowplaying",
diff --git a/src/settings.h b/src/settings.h
index 6cb4cb2..8ce1225 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -96,7 +96,7 @@ typedef struct {
char *npStationFormat;
char *listSongFormat;
char *fifo;
- char *tlsCaPath;
+ char tlsFingerprint[20];
BarMsgFormatStr_t msgFormat[MSG_COUNT];
} BarSettings_t;