express: Update SHA256 code in ZipArchive for OpenSSL v3

This commit is contained in:
rdb 2025-10-15 11:42:38 +02:00
parent 5f9bb65505
commit 25ef6112de
4 changed files with 77 additions and 14 deletions

View File

@ -571,11 +571,11 @@ add_jar_signature(X509 *cert, EVP_PKEY *pkey, const std::string &alias) {
const std::string header_digest = "VmrRqAIgAm0FCZViZFzpaP8OfDbN4iY0MyYFuzTMPv8=";
std::stringstream manifest;
SHA256_CTX manifest_ctx;
SHA256_Init(&manifest_ctx);
EVP_MD_CTX *manifest_ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(manifest_ctx, EVP_sha256(), nullptr);
manifest << header;
SHA256_Update(&manifest_ctx, header.data(), header.size());
EVP_DigestUpdate(manifest_ctx, header.data(), header.size());
std::ostringstream sigfile_body;
@ -594,20 +594,21 @@ add_jar_signature(X509 *cert, EVP_PKEY *pkey, const std::string &alias) {
{
std::istream *stream = open_read_subfile(subfile);
SHA256_CTX subfile_ctx;
SHA256_Init(&subfile_ctx);
EVP_MD_CTX *subfile_ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(subfile_ctx, EVP_sha256(), nullptr);
char buffer[4096];
stream->read(buffer, sizeof(buffer));
size_t count = stream->gcount();
while (count > 0) {
SHA256_Update(&subfile_ctx, buffer, count);
EVP_DigestUpdate(subfile_ctx, buffer, count);
stream->read(buffer, sizeof(buffer));
count = stream->gcount();
}
delete stream;
SHA256_Final(digest, &subfile_ctx);
EVP_DigestFinal_ex(subfile_ctx, digest, nullptr);
EVP_MD_CTX_free(subfile_ctx);
}
// Encode to base64.
@ -616,24 +617,21 @@ add_jar_signature(X509 *cert, EVP_PKEY *pkey, const std::string &alias) {
// Encode what we just wrote to the manifest file as well.
{
unsigned char digest[SHA256_DIGEST_LENGTH];
SHA256_CTX section_ctx;
SHA256_Init(&section_ctx);
SHA256_Update(&section_ctx, section.data(), section.size());
SHA256_Final(digest, &section_ctx);
EVP_Digest(section.data(), section.size(), digest, nullptr, EVP_sha256(), nullptr);
sigfile_body << "SHA-256-Digest: " << base64_encode(digest, SHA256_DIGEST_LENGTH) << "\r\n\r\n";
}
manifest << section;
SHA256_Update(&manifest_ctx, section.data(), section.size());
EVP_DigestUpdate(manifest_ctx, section.data(), section.size());
}
// The hash for the whole manifest file goes at the beginning of the .SF file.
std::stringstream sigfile;
{
unsigned char digest[SHA256_DIGEST_LENGTH];
SHA256_Final(digest, &manifest_ctx);
EVP_DigestFinal_ex(manifest_ctx, digest, nullptr);
EVP_MD_CTX_free(manifest_ctx);
sigfile << "Signature-Version: 1.0\r\n";
sigfile << "SHA-256-Digest-Manifest-Main-Attributes: " << header_digest << "\r\n";
sigfile << "SHA-256-Digest-Manifest: " << base64_encode(digest, SHA256_DIGEST_LENGTH) << "\r\n\r\n";

21
tests/express/cert.pem Normal file
View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDZTCCAk2gAwIBAgIULuBiiqTjDq8eK6pCRMLMTtV5tRUwDQYJKoZIhvcNAQEL
BQAwQjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UE
CgwTRGVmYXVsdCBDb21wYW55IEx0ZDAeFw0yNTEwMTUwOTA3MDhaFw0yNjEwMTUw
OTA3MDhaMEIxCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAa
BgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQCjCpKGVRGDaAkdb+Fl7NYv6/d3QEp3HDDN0I8Ns5xBPRlvsnUm
uPcv+VZRtgM8DXFyypqmbknHeayWBwcAdvEor3JsRLYpB+buZl48Sr7rOQMbP3xG
da0XYMA3JNW4MSf7VfNbq9tBcXM+JGHZgyEFkmKPxxdwjJC0g90zOBRlTmmOjI1H
Aus1hTQXeCxkbkTIjggxU5e6ptx4EOpaWotLLIWbuFx9rLTcbuQVx4Pwu+DuRcCp
eXsnWcS/wcGQSUF1586zu6oAFBgv8XPmskzOphK0Ei8eDwyfIHxqF/ej0NAJei1Q
hePOh+fX2eLh6kH4sAc2mFtLbnURxwz3b03tAgMBAAGjUzBRMB0GA1UdDgQWBBT7
KryYClrgtH/oF518izizsMfX1DAfBgNVHSMEGDAWgBT7KryYClrgtH/oF518iziz
sMfX1DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA+JH1el4P8
ofA5Us4LBJNS82KJY96dSITKE3W7R6IZj0TZPYgE244eeN/wdbu1QsFrXXS7jYYY
npLlVouiC26aMNIrNoRa0rHqJA7shR4+1iT3hawu8zYH55kooOgZwn8mRe1G7XD+
TrvFYvgjNi5AgISqkmfuXyzcOfSZ7jt/mv7rVSSs9N1ZVrNOAGDnFN1YLAVXD9eh
cH2i0SrtmFYnK+xYvK/eT1EGngtTdsBwD/GGoaPuuGU9sWVswcR9Gp/FgQBB31ZK
Edeyh2IdydBlHRSzpJkhnUtyJBN29+/P3WW27XUYDyfSma+0X7G8qAWsyBG7qWXi
fIU+/gpvLoNC
-----END CERTIFICATE-----

28
tests/express/private.pem Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCjCpKGVRGDaAkd
b+Fl7NYv6/d3QEp3HDDN0I8Ns5xBPRlvsnUmuPcv+VZRtgM8DXFyypqmbknHeayW
BwcAdvEor3JsRLYpB+buZl48Sr7rOQMbP3xGda0XYMA3JNW4MSf7VfNbq9tBcXM+
JGHZgyEFkmKPxxdwjJC0g90zOBRlTmmOjI1HAus1hTQXeCxkbkTIjggxU5e6ptx4
EOpaWotLLIWbuFx9rLTcbuQVx4Pwu+DuRcCpeXsnWcS/wcGQSUF1586zu6oAFBgv
8XPmskzOphK0Ei8eDwyfIHxqF/ej0NAJei1QhePOh+fX2eLh6kH4sAc2mFtLbnUR
xwz3b03tAgMBAAECggEAR8txCFxPcPkQAnlw3Mw06TdUapvR7q9oQklTpSnxZbz9
BXWlJt8OYn6+Zw7qT7hvu6fCAAXS0VcgC5SenbLCsTLJBSoguOK060gCuTQE7FnX
p1kGZZSOGxxMqDu9LPXgcEnB9x0vWJsXr0agHAMlOGnkowF9rd8IHaVvc41/VbhD
kH9mWSlX8jSFZnN3pTJUygpA3/m2fBzs+WWacGukF0c3TNgbXpmf2ODxrqCWsf0e
kv7CW1X64g9T/UPoIXCaaAFwM6AzfykEHvty5Yac2WRavTSSxw619vtNGK6Sw7se
SJo9tykxXa1emhEl+AlHkOz4AqPJ+BXZv3IVBiswtQKBgQDlzPKdNPlIQlEsJXrE
3evmOL8ACqnSQG2kof2ouEBE6Z09e4Wm2VA6SBV4soPiVyOcKZp58ZNiU9MIHVl2
OKvT1AhsKID2cIYjGYvmr7+IpHqqklAMy3K+EtT6oUGu/Js3wlmxG9KJnCtxGwIH
QjizqaUoAZKwj/j5ZWQPxLYdUwKBgQC1oSlTTVvd+tGtEKXyeG5/xTpQpjyRnKWp
bof2Apj6zaWKx6EWAdmLB7uIk4J1rQqCdEVSbUZ+PGcl1flKoSfSWFOtnb0pdU91
70WS4hz2ABgMuRlOh1xCk0YaoIpR5My+KsoHQngAqChj5rlcLTS2hJTUcQjItSB3
tuQf8Ug/vwKBgEaA8bKvzQeRaSwdN6Rs3fJdWKRfoSijocAP/y4jkXxTHG3/lsrR
A59N/GByjKoFyCQiU4W0S16wjx9/ObJewsET3Z2pc5+oeE8OiHC3XRFEPWpVx3+V
b9fHGVbn4KoaUFj0JOaEvbyAkId8HMwzUgg1NTmn+eR315BUvjVkSeeHAoGBALUV
ZNpEul7qfroJayn/oEuLG8TkuGaEwzXVmYBQvqzu8ykWNyh116qhnvtf9iXUzDGc
MrEneazKFBzI5K7fVZCFt4fVSI9ZAkwWrkrvXOh214N32B9PHVDS/IX3oXBcqTS/
/ISYZIRjI0HW+t9HwtJmBOx5dcSFsUUp9u9R5DKJAoGBAMWEsK5lMz0FFr9g9OLD
lARC8iYtFSgL2klINxeMT3lzhB/7baIoEYbgWNcHWw/qB+li3QGpDn+tlilNHIzU
Y1LTEJFMjoHLanA7qskhkziyVIL5z4VCsguArUHamGajT3ZQ03814rG0OUk7wHfk
9ZN06G0/Ot4cPZEc5Jy6E4pS
-----END PRIVATE KEY-----

View File

@ -2,6 +2,7 @@ from panda3d.core import ZipArchive, IStreamWrapper, StringStream, Filename
from direct.stdpy.file import StreamIOWrapper
import zipfile
from io import BytesIO
import os
EMPTY_ZIP = b'PK\x05\x06' + b'\x00' * 18
@ -181,3 +182,18 @@ def test_zip_repack(tmp_path):
assert zf.read("test1.txt") == b"contents of first file"
assert "test2.txt" not in zf.namelist()
assert zf.read("test3.txt") == b"contents of third file"
def test_zip_jar_signature():
cur_dir = Filename.from_os_specific(os.path.dirname(__file__))
stream = StringStream()
zip = ZipArchive()
zip.open_read_write(stream)
zip.add_subfile("test.txt", StringStream(b"contents of test file"), 6)
zip.add_jar_signature(Filename(cur_dir, "cert.pem"), Filename(cur_dir, "private.pem"))
zip.close()
with zipfile.ZipFile(StreamIOWrapper(stream), 'r') as zf:
assert zf.read("META-INF/MANIFEST.MF") == b'Manifest-Version: 1.0\r\n\r\nName: test.txt\r\nSHA-256-Digest: k5XWgStAZvRlNWIcz67qLSzso8Mc+OUG1QOlAwysyhE=\r\n\r\n'
assert zf.read("META-INF/CERT.SF") == b'Signature-Version: 1.0\r\nSHA-256-Digest-Manifest-Main-Attributes: VmrRqAIgAm0FCZViZFzpaP8OfDbN4iY0MyYFuzTMPv8=\r\nSHA-256-Digest-Manifest: 9R83KbhgHCBaYGXhJ/bV2MofgjRU254oUx+YilOvRcE=\r\n\r\nName: test.txt\r\nSHA-256-Digest: q8FmiLsrdoC5XQRaN9KmaPCcd2revsR0NzDul9cK6bk=\r\n\r\n'