Verify the signatures of spotify blob files downloaded at runtime. Should protect against MITM attacks, and compromises of our server.
This commit is contained in:
parent
a2327c4eb7
commit
c12b3ab399
|
@ -68,6 +68,7 @@ pkg_check_modules(LIBMTP libmtp>=1.0)
|
|||
pkg_check_modules(INDICATEQT indicate-qt)
|
||||
pkg_check_modules(SPOTIFY libspotify>=0.0.8)
|
||||
pkg_check_modules(CDIO libcdio)
|
||||
pkg_check_modules(QCA qca2)
|
||||
|
||||
if (WIN32)
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
@ -233,9 +234,9 @@ if(ENABLE_BREAKPAD)
|
|||
set(HAVE_BREAKPAD ON)
|
||||
endif(ENABLE_BREAKPAD)
|
||||
|
||||
if(ENABLE_SPOTIFY AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE)
|
||||
if(ENABLE_SPOTIFY AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE AND QCA_FOUND)
|
||||
set(HAVE_SPOTIFY ON)
|
||||
endif(ENABLE_SPOTIFY AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE)
|
||||
endif(ENABLE_SPOTIFY AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE AND QCA_FOUND)
|
||||
|
||||
if(ENABLE_SPOTIFY_BLOB AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE AND SPOTIFY_FOUND)
|
||||
set(HAVE_SPOTIFY_BLOB ON)
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqAvoUlyct8cM/dM5OBwP
|
||||
sqXNJEbxdMsbtX8fXErcj+r1qSlOG1KtFZmVXw8FZtq3WQddgb95w/T8zvP1v0dt
|
||||
6ZbsYlsE+TqTiTcN1rpbVi33SpcWGZ7d2o+bbTEaVagVuwccPDvfMu005/zzFl0f
|
||||
iRVg2zLkFYuLRDZpOwbgw7KBKTVqaB/aeRK/sjXSjaZdizuxW4WnmKYWML3h4RpZ
|
||||
kg5+faMQiG9sA0iH27PzXPZWVG9Py2ypyVA4pSQIZFveYbr9XpcxPhcEalXbxNU8
|
||||
S7OzDbWmjNIh7KCMy2F7NxnW92b+7WRUcjp953U2LKtcppZK3AOlnETzkHcmB7cD
|
||||
sQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
|
@ -329,5 +329,6 @@
|
|||
<file>providers/grooveshark.png</file>
|
||||
<file>allthethings.png</file>
|
||||
<file>globalsearch.css</file>
|
||||
<file>clementine-spotify-public.pem</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -709,6 +709,8 @@ optional_source(HAVE_SPOTIFY
|
|||
internet/spotifyservice.h
|
||||
internet/spotifysettingspage.h
|
||||
resolvers/spotifyresolver.h
|
||||
INCLUDE_DIRECTORIES
|
||||
${QCA_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
# Platform specific - OS X
|
||||
|
@ -1047,6 +1049,7 @@ if(HAVE_SPOTIFY)
|
|||
target_link_libraries(clementine_lib
|
||||
clementine-spotifyblob-messages
|
||||
gstspotifytcpsrc
|
||||
${QCA_LIBRARIES}
|
||||
)
|
||||
endif(HAVE_SPOTIFY)
|
||||
|
||||
|
|
|
@ -19,11 +19,16 @@
|
|||
#include "spotifyservice.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/network.h"
|
||||
#include "core/utilities.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkReply>
|
||||
#include <QProgressDialog>
|
||||
#include <QtCrypto>
|
||||
|
||||
const char* SpotifyBlobDownloader::kSignatureSuffix = ".sha1";
|
||||
|
||||
|
||||
SpotifyBlobDownloader::SpotifyBlobDownloader(
|
||||
const QString& version, const QString& path, QObject* parent)
|
||||
|
@ -56,7 +61,10 @@ void SpotifyBlobDownloader::Start() {
|
|||
qDeleteAll(replies_);
|
||||
replies_.clear();
|
||||
|
||||
const QStringList filenames = QStringList() << "blob" << "libspotify.so.8";
|
||||
const QStringList filenames = QStringList()
|
||||
<< "blob"
|
||||
<< "blob" + QString(kSignatureSuffix)
|
||||
<< "libspotify.so.8";
|
||||
|
||||
foreach (const QString& filename, filenames) {
|
||||
const QUrl url(SpotifyService::kBlobDownloadUrl + version_ + "/" + filename);
|
||||
|
@ -87,12 +95,14 @@ void SpotifyBlobDownloader::ReplyFinished() {
|
|||
}
|
||||
}
|
||||
|
||||
// Make the destination directory and write the files into it
|
||||
QDir().mkpath(path_);
|
||||
// Let's verify signatures in a temporary directory first, before we write
|
||||
// anything into its final position.
|
||||
QString temp_directory = Utilities::MakeTempDir();
|
||||
QStringList signatures;
|
||||
|
||||
foreach (QNetworkReply* reply, replies_) {
|
||||
const QString filename = reply->url().path().section('/', -1, -1);
|
||||
const QString path = path_ + "/" + filename;
|
||||
const QString path = temp_directory + "/" + filename;
|
||||
|
||||
qLog(Info) << "Saving file" << path;
|
||||
QFile file(path);
|
||||
|
@ -101,10 +111,69 @@ void SpotifyBlobDownloader::ReplyFinished() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (path.endsWith(kSignatureSuffix)) {
|
||||
signatures << path;
|
||||
}
|
||||
|
||||
file.setPermissions(QFile::Permissions(0x7755));
|
||||
file.write(reply->readAll());
|
||||
}
|
||||
|
||||
// Load the public key
|
||||
QCA::ConvertResult conversion_result;
|
||||
QCA::PublicKey key = QCA::PublicKey::fromPEMFile(":/clementine-spotify-public.pem",
|
||||
&conversion_result);
|
||||
if (QCA::ConvertGood != conversion_result) {
|
||||
ShowError("Failed to load Spotify public key");
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify signatures
|
||||
foreach (const QString& signature_filename, signatures) {
|
||||
QString filename = signature_filename;
|
||||
filename.remove(kSignatureSuffix);
|
||||
|
||||
qLog(Debug) << "Verifying" << filename << "against" << signature_filename;
|
||||
|
||||
QFile actual_file(filename);
|
||||
if (!actual_file.open(QIODevice::ReadOnly))
|
||||
return;
|
||||
|
||||
QFile signature_file(signature_filename);
|
||||
if (!signature_file.open(QIODevice::ReadOnly))
|
||||
return;
|
||||
|
||||
if (!key.verifyMessage(actual_file.readAll(), signature_file.readAll(),
|
||||
QCA::EMSA3_SHA1)) {
|
||||
ShowError("Invalid signature: " + filename);
|
||||
return;
|
||||
}
|
||||
|
||||
qLog(Debug) << "Verification OK";
|
||||
}
|
||||
|
||||
// Make the destination directory and write the files into it
|
||||
QDir().mkpath(path_);
|
||||
|
||||
foreach (QNetworkReply* reply, replies_) {
|
||||
const QString filename = reply->url().path().section('/', -1, -1);
|
||||
const QString source_path = temp_directory + "/" + filename;
|
||||
const QString dest_path = path_ + "/" + filename;
|
||||
|
||||
if (filename.endsWith(kSignatureSuffix))
|
||||
continue;
|
||||
|
||||
qLog(Info) << "Moving" << source_path << "to" << dest_path;
|
||||
|
||||
if (!QFile::rename(source_path, dest_path)) {
|
||||
ShowError("Writing file failed: " + dest_path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the temporary directory
|
||||
Utilities::RemoveRecursive(temp_directory);
|
||||
|
||||
EmitFinished();
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ public:
|
|||
QObject* parent = 0);
|
||||
~SpotifyBlobDownloader();
|
||||
|
||||
static const char* kSignatureSuffix;
|
||||
|
||||
static bool Prompt();
|
||||
|
||||
void Start();
|
||||
|
|
|
@ -78,6 +78,10 @@ using boost::scoped_ptr;
|
|||
|
||||
#include <echonest/Config.h>
|
||||
|
||||
#ifdef HAVE_SPOTIFY
|
||||
#include <QtCrypto>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
@ -369,6 +373,10 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SPOTIFY
|
||||
QCA::Initializer qca_initializer;
|
||||
#endif
|
||||
|
||||
// Resources
|
||||
Q_INIT_RESOURCE(data);
|
||||
Q_INIT_RESOURCE(translations);
|
||||
|
|
|
@ -566,7 +566,7 @@ msgstr ""
|
|||
msgid "Always start playing"
|
||||
msgstr ""
|
||||
|
||||
#: internet/spotifyblobdownloader.cpp:50
|
||||
#: internet/spotifyblobdownloader.cpp:55
|
||||
msgid ""
|
||||
"An additional plugin is required to use Spotify in Clementine. Would you "
|
||||
"like to download and install it now?"
|
||||
|
@ -793,7 +793,7 @@ msgstr ""
|
|||
msgid "CUE sheet support"
|
||||
msgstr ""
|
||||
|
||||
#: internet/spotifyblobdownloader.cpp:34
|
||||
#: internet/spotifyblobdownloader.cpp:39
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1432,7 +1432,7 @@ msgstr ""
|
|||
msgid "Downloading Magnatune catalogue"
|
||||
msgstr ""
|
||||
|
||||
#: internet/spotifyblobdownloader.cpp:34
|
||||
#: internet/spotifyblobdownloader.cpp:39
|
||||
msgid "Downloading Spotify plugin"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1584,7 +1584,7 @@ msgstr ""
|
|||
msgid "Error deleting songs"
|
||||
msgstr ""
|
||||
|
||||
#: internet/spotifyblobdownloader.cpp:137
|
||||
#: internet/spotifyblobdownloader.cpp:205
|
||||
msgid "Error downloading Spotify plugin"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3696,7 +3696,7 @@ msgstr ""
|
|||
msgid "Spotify plugin"
|
||||
msgstr ""
|
||||
|
||||
#: internet/spotifyblobdownloader.cpp:49
|
||||
#: internet/spotifyblobdownloader.cpp:54
|
||||
msgid "Spotify plugin not installed"
|
||||
msgstr ""
|
||||
|
||||
|
|
Loading…
Reference in New Issue