updater: move signature back to just the binary

Yes, makes it cryptographically weaker, but somebody who can modify responses of my webserver has probably enough power to access gitlab secrets already. The signature is pretty "optional" then.
This commit is contained in:
Moritz Zwerger 2024-01-09 07:39:40 +01:00
parent 2548b5c027
commit c6978abe10
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
7 changed files with 24 additions and 25 deletions

View File

@ -29,7 +29,7 @@ Otherwise it responds with `200 OK` and returns a json object (with the signatur
"url": "https:// where to download it",
"size": <Update size in Bytes>,
"sha512": "SHA512 hash of the binary",
"signature": "Release signature"
"signature": "SHA512withRSA signature of the binary"
},
"release_notes": "<Optional text for release notes to show in the client>"
}
@ -45,10 +45,6 @@ Once it is downloaded, minosoft asks the user to restart. It will then quit and
The client will refuse to update, if the release date of the next version is lower than the version currently running (i.e. no downgrades)
## Signature
The first line of the file is the base64 encoded signature of the whole json object.
## Future
- Maybe split the fat jar and download all dependencies individual (reduces size of the binary; lowers traffic)

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
* Copyright (C) 2020-2024 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@ -13,26 +13,27 @@
package de.bixilon.minosoft.updater
import org.testng.Assert.assertThrows
import org.testng.annotations.Test
@Test(groups = ["updater"])
class MinosoftUpdaterTest {
private fun verify(signature: String, data: String) {
MinosoftUpdater.parse(signature + "\n" + data)
/*
private fun verify(data: String) {
MinosoftUpdater.parse(data)
}
fun `verify broken signature`() {
assertThrows { verify("NOT_VALID", """{"id":"dummy","name":"Dummy version","date":-1,"stable":true,"page":null,"download":{"url":"https://bixilon.de/secret-update.jar","size":123,"sha512":"b8244d028981d693af7b456af8efa4cad63d282e19ff14942c246e50d9351d22704a802a71c3580b6370de4ceb293c324a8423342557d4e5c38438f0e36910ee"},"release_notes":":)"}""") }
assertThrows { verify("""{"id":"dummy","name":"Dummy version","date":-1,"stable":true,"page":null,"download":{"url":"https://bixilon.de/secret-update.jar","size":123,"sha512":"b8244d028981d693af7b456af8efa4cad63d282e19ff14942c246e50d9351d22704a802a71c3580b6370de4ceb293c324a8423342557d4e5c38438f0e36910ee"},"release_notes":":)"}""", "NOT_VALID") }
}
fun `verify correct signature`() {
assertThrows {
verify(
"Mv7979ky1AlMCcOLmX+Zdmo2Y7YOGiMthTBeNP2jKUPRkMtX1GCBYMrsKV+si9rR9Kg+1Ns82Hw1iYAI+ZOkTzVmoIeaWkqL4PN4sCCVllm2ZmZhTap7wdNAVEjW197Cf+V2YJW0TsG+j2s6OK86gdtVmyJ96X/ENhXTJRp8pW50lcCyy95ipQ1Qe8v4mAFykpU9XC/yU2Mhil/KznxvxKgd7N4+/VNpubOHetWfdiz9jqAB6uaYVi0H9E+EoZodkG3Iy5uagr1OrWNiwjk3LQUEk+J+5cYRPqBHrqLM9VNQFa5BqysSJoW7cIo/QUQA47EBxO8Rmg/juFA1l9bXtSUA+1j12n9ImhE/L3cYseYiIN8GFRpbhSaROgfZW9u3lVHM4g45q67zvvdf+Eo7lqfipYio89rQ984U58o5AvLhV+WqhDVRBTTtO+oI/FjdiHIruoiY/adEz7gJEAlrMlgoAAQkVnKma9uufObIemL+QGpDjLvdluIgts/cT34r4I5Xaij1vGAjzZ+Fe+Tn5tuW48pjtjWCzAwVTEu/zf/VKSJPoCVGx5YCvFE3CKXkVWuJ86gj+rO/SXWkjv672EetaVwv2Uc/RkCfru84m6bQWAHzb3P46Hfkw3kIyaIudxgizy1xlxLEEU3LwUU/vFxTd2Q6lAhGGMn6Imy9Z6I=",
"""{"id":"dummy","name":"Dummy version","date":-1,"stable":true,"page":null,"download":{"url":"https://bixilon.de/secret-update.jar","size":123,"sha512":"b8244d028981d693af7b456af8efa4cad63d282e19ff14942c246e50d9351d22704a802a71c3580b6370de4ceb293c324a8423342557d4e5c38438f0e36910ee"},"release_notes":":)"}""")
"""{"id":"dummy","name":"Dummy version","date":-1,"stable":true,"page":null,"download":{"url":"https://bixilon.de/secret-update.jar","size":123,"sha512":"b8244d028981d693af7b456af8efa4cad63d282e19ff14942c246e50d9351d22704a802a71c3580b6370de4ceb293c324a8423342557d4e5c38438f0e36910ee"},"release_notes":":)"}""",
"Mv7979ky1AlMCcOLmX+Zdmo2Y7YOGiMthTBeNP2jKUPRkMtX1GCBYMrsKV+si9rR9Kg+1Ns82Hw1iYAI+ZOkTzVmoIeaWkqL4PN4sCCVllm2ZmZhTap7wdNAVEjW197Cf+V2YJW0TsG+j2s6OK86gdtVmyJ96X/ENhXTJRp8pW50lcCyy95ipQ1Qe8v4mAFykpU9XC/yU2Mhil/KznxvxKgd7N4+/VNpubOHetWfdiz9jqAB6uaYVi0H9E+EoZodkG3Iy5uagr1OrWNiwjk3LQUEk+J+5cYRPqBHrqLM9VNQFa5BqysSJoW7cIo/QUQA47EBxO8Rmg/juFA1l9bXtSUA+1j12n9ImhE/L3cYseYiIN8GFRpbhSaROgfZW9u3lVHM4g45q67zvvdf+Eo7lqfipYio89rQ984U58o5AvLhV+WqhDVRBTTtO+oI/FjdiHIruoiY/adEz7gJEAlrMlgoAAQkVnKma9uufObIemL+QGpDjLvdluIgts/cT34r4I5Xaij1vGAjzZ+Fe+Tn5tuW48pjtjWCzAwVTEu/zf/VKSJPoCVGx5YCvFE3CKXkVWuJ86gj+rO/SXWkjv672EetaVwv2Uc/RkCfru84m6bQWAHzb3P46Hfkw3kIyaIudxgizy1xlxLEEU3LwUU/vFxTd2Q6lAhGGMn6Imy9Z6I=")
}
}
*/
}

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
* Copyright (C) 2020-2024 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@ -45,7 +45,7 @@ class UpdaterC(profile: OtherProfile) {
* - OS: Operating system (windows, linux, mac, ...)
* - ARCH: architecture of the current build (x86, x64, arm64)
*/
var url by StringDelegate(profile, "https://minosoft.bixilon.de/v1/updates?version=\${VERSION}&channel=\${CHANNEL}&commit=\${COMMIT}&os=\${OS}&arch=\${ARCH}")
var url by StringDelegate(profile, "https://minosoft.bixilon.de/api/v1/updates?version=\${VERSION}&channel=\${CHANNEL}&commit=\${COMMIT}&os=\${OS}&arch=\${ARCH}")
/**
* If the newest version matches this field, it won't be shown

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
* Copyright (C) 2020-2024 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@ -19,4 +19,5 @@ data class DownloadLink(
val url: URL,
val size: Int,
val sha512: String,
val signature: String,
)

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
* Copyright (C) 2020-2024 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@ -101,9 +101,7 @@ object MinosoftUpdater {
}
fun parse(data: String): MinosoftUpdate {
val (signature, json) = data.split('\n', limit = 2)
UpdateKey.require(signature, json)
return Jackson.MAPPER.readValue(json, MinosoftUpdate::class.java)
return Jackson.MAPPER.readValue(data, MinosoftUpdate::class.java)
}
fun download(update: MinosoftUpdate, progress: UpdateProgress) {
@ -116,5 +114,6 @@ object MinosoftUpdater {
progress.log?.print("TODO :)")
progress.stage = UpdateProgress.UpdateStage.FAILED
// UpdateKey.require(data, signature)
}
}

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
* Copyright (C) 2020-2024 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@ -15,5 +15,6 @@ package de.bixilon.minosoft.util.http
class HTTPResponse<T>(
val statusCode: Int,
val headers: Map<String, String>,
val body: T,
)

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
* Copyright (C) 2020-2024 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@ -42,22 +42,23 @@ abstract class SignatureSigner(
return instance
}
open fun verify(data: ByteArray, signature: ByteArray): Boolean {
open fun verify(data: ByteArray, signature: ByteArray?): Boolean {
if (signature == null) return false
val instance = createInstance()
instance.update(data)
return instance.verify(signature)
}
fun require(data: ByteArray, signature: ByteArray) {
fun require(data: ByteArray, signature: ByteArray?) {
if (verify(data, signature)) return
throw SignatureException()
}
fun verify(data: String, signature: String): Boolean {
fun verify(data: String, signature: String?): Boolean {
return verify(data.toByteArray(), Base64.getDecoder().decode(signature))
}
fun require(data: String, signature: String) {
fun require(data: String, signature: String?) {
if (verify(data, signature)) return
throw SignatureException()
}