可复制且仅限源的tarball

使用Libntlm版本1.8的发布发布tarball可以在多个发行版上复制。我们还发布了一个由git档案与使用的格式相同大草原,Codeberg公司,GitLab公司,github和其他。测试了两种柏油球的再现性持续进行回归通过CI/CD管道在GitLab上运行。如果这还不足以让你兴奋Libntlm的Debian包现在是从可复制的最小源代码tarball构建的。生成的二进制文件是可复制的在多个架构上。

这意味着什么?你为什么要在乎?你如何能为你的项目做同样的事情?存在哪些未决问题?亲爱的读者,继续读下去…

本文描述了我对可复制发布工件的实际实验我早先的想法导致关于化石的讨论和aJanneke Nieuwenhuizen制作的补丁,使吉他柏油球可重复使用这启发了我做一些实际工作。

让我们看看维护人员如何发布一些软件,以及用户如何从源代码中重现发布的工件。Libntlm提供了一个用C编写的共享库,并使用GNU品牌,GNU自动控制,可移植的源代码,GNU库工具格努利布对于构建管理,但这些思想应适用于大多数项目和构建系统。以下说明了维护人员准备发布时要采取的步骤:

git克隆https://gitlab.com/gsasl/libntlm.git网站光盘库git校验v1.8./引导./配置进行分发检查gpg-b libntlm-1.8tar.gz

生成的文件libntlm-1.8tar.gz银行libntlm-1.8.tar.gz.sig发布,用户下载并使用它们。这就是如何GNU项目自20世纪80年代末以来一直在发行。这证明了这种模式是多么成功!这些tarball包含源代码和一些生成的文件,通常是autoconf生成的shell脚本、automake生成的makefile模板、以下格式的文档信息、HTML或PDF。它们很少包含二进制目标代码,但历史上确实如此。

这个XZUtils事件说明包含git存档中未包含的文件的tarball提供了伪装恶意后门的机会。早些时候写过博客如何通过使用签名的最小源代码tarball来降低此风险。

隐藏恶意软件的风险并不是发布签名的最小源代码tarball的唯一动机。使用tarball中预先生成的内容,存在以下风险GNU/Linux发行版例如特里斯克尔,吉他,Debian公司/Ubuntu公司费多拉将从tarball生成的文件发送到二进制文件*.deb(代布)*.转/分程序包文件。通常,打包上游项目的人员从未意识到某些已安装的工件不是通过典型的autoconf-fi和&/配置并进行安装序列,并且从未编写代码来重建所有内容。如果构建规则被编写但有缺陷,并且运送了旧的工件,也会发生这种情况。当发现安全问题时,这可能会导致耗时的情况,因为修补相关源代码并重新构建包可能是不够的:从tarball生成的易受攻击的对象将被发送到二进制包中,而不是重新构建的工件中。对于特定于体系结构的二进制文件,这种情况很少发生,因为目标代码通常不包含在tarballs中,尽管十多年来我在GNU图书馆释放tarball,直到我停止运输对于解释语言,尤其是生成的内容,如HTML、PDF、shell脚本,这种情况发生得比您希望的要多。

发布最小的源代码tarball可以更容易地审核项目代码,从而避免需要通读所有生成的文件以查找恶意内容。我已经使用生成了源代码的最小tarballgit存档这与GitLab、GitHub等为git标签上的自动下载链接提供的格式相同。因此,最小的源代码tarball可以作为审核GitLab和GitHub下载材料的一种方式!考虑GitLab或GitHub等托管站点是否/何时发生安全事件,导致生成的tarball包含git存储库中不存在的后门。如果人们依赖标签下载工件而没有使用验证维护者PGP签名保密性卫兵,这可能会导致类似于XZUtils的后门场景,但源于托管提供商而不是发布管理器。这更令人担忧,因为此攻击可能针对某些选定的IP地址,而不是针对所有人,因此很难发现。

在所有这些讨论和基本原理都解决之后,让我们回到发布过程。我在这里添加了另一个步骤:

制作srcdistgpg-b库ntlm-1.8-src.tar.gz

现在发布准备就绪。我将这四个文件发布在Libntlm的Savannah下载区,但它们也可以上传到GitLab/GitHub发布区。这些是在我的计算机上构建tarball后得到的SHA256校验和Trisquel 11 aramo笔记本电脑:

91de864224913b9493c7a6cec2890e6eded3610d34c3d983132823de348ec2ca libntlm-1.8-src.tar.gzce6569a47a21173ba69c990965f73eb82d9a093eb871f935ab64ee13df47fda1 libntlm-1.8tar.gz

那么你如何重现我的作品呢?以下是如何在Ubuntu 22.04容器中复制它们:

播客运行它--rm ubuntu:22.04更新源apt-get安装-y--无安装-推荐autoconf automake libtool生成git ca证书git克隆https://gitlab.com/gsasl/libntlm.git网站光盘库git校验v1.8./引导./配置生成dist srcdist沙256sum libntlm-*.tar.gz

您应该会看到完全相同的SHA256校验和值。万岁!

这是因为Trisquel 11和Ubuntu 22.04使用了相同版本的git、autoconf、automake和libtool。这些工具并不能保证所有版本的输出内容相同全球导航卫星系统不会为所有版本生成相同的二进制输出。所以仍然需要一些微妙的版本配对。

理想情况下,工件应该可以从发布工件本身复制,而不仅仅是直接从git复制。可以在AlmaLinux公司8个容器–更换almalinux:8具有rockylinux:8如果你愿意RockyLinux:

podman run-it--rm almalinux:8dnf更新-ydnf安装-y make wget gccwget公司https://download.savannah.nongu.org/releases/libntlm/libntlm-1.8tar.gz焦油xfa libntlm-1.8tar.gz光盘libntlm-1.8./配置制造距离沙256sum libntlm-1.8tar.gz

可以在上重新生成仅源的最小tarballDebian 11号机组:

播客运行--rm debian:11更新源apt-get安装-y--无安装-建议生成git ca证书git克隆https://gitlab.com/gsasl/libntlm.git网站光盘库git校验v1.8make-f cfg.mk srcdist沙256sum libntlm-1.8-src.tar.gz

作为Magnus Opus或chef-d'œuvre,让我们直接从Trisquel 11上的最小源代码tarball重新创建完整的tarball–replacedocker.io/kpengboy/trisquel:11.0具有乌班图:22.04如果你愿意的话。

播客运行它--rm docker.io/kpengboy/trisquel:11.0更新源apt-get安装-y--无安装-推荐autoconf automake libtool生成wget-git ca证书wget公司https://download.savannah.nongu.org/releases/libntlm/libntlm-1.8-src.tar.gztar xfa libntlm-1.8-src.tar.gz光盘libntlm-v1.8./引导./配置制造距离沙256sum libntlm-1.8tar.gz

耶!现在,您应该非常确信,发布工件与版本控制中的内容以及维护者打算发布的内容相对应。剩下的工作是审核源代码中的漏洞,包括构建中使用的依赖项的源代码。您不再需要担心审核发布工件。

我觉得有点有趣的是,Libntlm的构建基础设施现在比代码本身要好得多。Libntlm是用旧的C风格编写的,有大量的字符串操作,并使用了诸如MD4公司单个DES记住各位:解决供应链安全问题与您最终运行的代码类型无关。一支干净的枪仍然可以射中你的脚。

关于命名的旁注:GitLab使用路径名导出tarballlibntlm-v1.8型/(即。。,TAG项目/)我采用了相同的路径名,这意味着我的libntlm-1.8-src.tar.gz数据库tarball与GitLab的导出完全相同,您可以使用以下工具进行验证差速器GitLab命名tarballlibntlm-v1.8.tar.gz数据库(即。,项目-标签。档案文件)我发现它与libntlm-1.8tar.gz银行我们也发布了。GitHub使用相同的git存档样式,但不幸的是,它们的逻辑删除了路径名中的“v”,因此您将得到一个带有路径名的tarball伦敦银行-1.8/而不是libntlm-v1.8型/我和GitLab使用的。tarball的内容是逐位相同的,但路径名和存档不同。Codeberg(运行福吉乔)使用另一种方法:tarball被称为libntlm-v1.8.tar.gz数据库(在标记之后)就像GitLab一样,但归档文件中的路径名是利本特姆/,否则生成的存档将逐位相同,包括时间戳。萨凡纳的CGIT接口使用存档名称libntlm-1.8tar.gz银行具有路径名伦敦银行-1.8/,否则文件内容相同。萨凡纳的GitWeb接口提供以git提交命名的快照链接(例如。,libntlm-a812c2ca.tar.gz公司具有libntlm-a812c2ca公司/)而且我根本找不到任何基于标签的下载链接。总的来说,我们非常接近于使SHA256校验和匹配,但在存档中的路径名上失败。我选择与GitLab兼容tarball的内容,但不兼容存档命名。从简单的角度来看,如果每个人都使用项目-标签。档案文件用于存档文件名和TAG项目/用于存档中的路径名。这方面可能需要更多讨论。

关于git存档输出的旁注:它似乎是不同版本的git存档为同一存储库生成不同的结果。Debian 11、Trisquel 11和Ubuntu 22.04中git的版本表现相同。Debian 12、AlmaLinux/RockyLinux 8/9、Alpine、ArchLinux、macOS自制软件和即将推出的Ubuntu 24.04中的git版本表现出了另一种方式。希望这不会经常发生变化,但这会使这些tarball在未来的再现性失效,迫使您使用旧的git发行版来重现源代码tarball。唉,GitLab和大多数其他网站似乎都在使用现代git,因此从他们那里下载的tarball与我的tarballs不匹配,即使内容会匹配。

ChangeLog上的旁注:ChangeLog文件通常是手动管理的文件,带有包的版本历史记录。近年来,有几个项目开始从git历史动态生成它们(使用诸如吉特2clgitlog到changelog). 这会影响tarball的可再现性:您需要有完整的git历史记录!这个gitlog到changelog工具也输出不同的输出取决于时区这是一个可以修复的简单错误。然而,这整个方法与从最小的源tarball重建完整的tarball不兼容。看起来Libntlm的ChangeLog文件死于手术台在这里。

那么,发行版如何构建这些最小的纯源tarball呢?我碰巧在Debian中的libntlm包它历史上使用生成的tarball作为构建源代码。这意味着来自gnulib的代码将在tarball中出售。当在gnulib代码中发现安全问题时,安全团队需要修补包括该供应商代码的所有包并重建它们,而不是仅仅修补gnulib包并重建依赖于该特定代码的所有包。为了改变这一点,Debian libntlm包需要依赖于Debian的gnulib包但有一个问题:与大多数使用gnulib的项目类似,Libntlm依赖于gnulib的特定git提交,而Debian只提供一个提交。对于要使用哪个提交,没有进行协调。已经采用了gnulib在Debian中,并添加git束*_所有.deb二进制包,以便依赖gnulib的项目可以选择他们需要的任何提交。这允许无网络GNULIB_URLGNULIB_修订运行Libntlm时的方法./引导安装了Debian gnulib包。否则,libntlm将获取Debian在gnulib包中碰巧拥有的任何最新版本的gnuib,而这并不是libntlm维护者想要使用的,并且随着时间的推移,可能会导致各种版本不匹配(从而导致安全问题)。Debian中的Libntlm是在Salsa上开发和测试的而且有持续集成测试感谢萨尔萨CI团队

关于git包的旁注:不幸的是,似乎没有可复制的方法将git存储库导出到一个或多个文件中。因此,所有这些工作的一个不幸后果是gnulib*.orig.tar.gz(原始目标.gz)Debian中的tarball不再可复制。我有尝试使Git包可复制,但我从未使其工作-请参阅中的注释gnulib的debian/README.source在这方面。当然,源tarball再现性与二进制无关gnulib在Debian中的再现性幸运的是,它本身。

一个悬而未决的问题是如何处理由这种方法触发的增加的构建依赖性。一些人们感到惊讶通过这种方式,但我不知道如何绕过它:如果您依赖另一个包中工具的源代码来构建您的包,那么隐藏这种依赖性是一个坏主意。很长一段时间以来,我们都是通过非最小tarball中的供应商代码来实现的。从引导的角度来看,Libntlm不是最关键的项目,因此添加git和gnulib作为生成取决于对它来说可能会很好。然而,考虑一下此模式是否用于其他使用gnulib的包,例如coreutils公司,gzip公司,焦油,野牛etc(都在使用gnulib),那么他们都会构建依赖项关于git和gnulib。因此,为新体系结构交叉构建这些包需要首先在该体系结构上使用git,这样可以快速循环。对gnulib的依赖是真实的,所以我不认为它会消失,而gnulab是一个架构:全部包裹。然而,对git的依赖仅仅是Debian-gnulib包如何选择使所有gnulib-git提交对项目可用的结果:通过git包。还有其他方法可以做到这一点,它不需要git工具来提取必要的文件,但我发现没有一种方法是可行的——欢迎提出想法!

最后是关于如何实现这一点的简要说明。通过gnulib实现可引导的源代码最小化tarball./引导通过使用GNULIB_修订机制,锁定使用的gnulib提交。我一直不喜欢git子模块,因为它们添加了额外的步骤,并且与CI/CD有复杂的交互放弃git子模块现在是因为要使用的特定提交没有记录在git存档使用git子模块时的输出。因此,必须在git存档tarball中的一些源代码中明确提到特定的gnulib提交。科林·沃森添加了GNULIB_REVISION接近./引导回到2018年,现在继续使用gnulib-git子模块已经没有意义了。一种替代方案是使用./引导具有--gnulib-srcdir--gnulib-refdir如果有一些实际问题GNULIB_URL朝向git捆绑包GNULIB_修订在里面引导.conf

这个srcdist生成规则很简单:

git存档--前缀=libntlm-v1.8/-o libntlm-1.8-src.tar.gz HEAD

制作制造距离生成的可复制tarball可能更复杂,但对于Libntlm来说,它足以确保所有文件的修改时间都是确定的到git存储库中最后一次提交的时间戳。有趣的是,似乎有两种不同的方法可以实现这一点,Guix不支持最小源代码tarball,但依靠.tarball时间戳tarball中的文件。保罗·艾金特解释了TZDB正在使用的内容不久前。这个我现在使用的方法我建议的一个一年多以前。如果由于tarball中的所有文件现在使用相同的修改时间而出现问题布鲁诺·海布尔的解决方案这是可以实现的。

关于git标签的旁注:有些人可能想知道为什么不验证签名的git标签,而不是验证git存档的签名tarball。目前大多数git存储库使用SHA-1作为git提交身份,但SHA-1不是安全哈希函数。虽然可以检测和缓解当前的SHA-1攻击,但人们基本上怀疑git SHA-1提交标识唯一地引用了预期的相同内容。验证git标记永远不会提供相同的保证,因为git标记可以随时移动或重新指定。验证git提交更好,但我们需要信任SHA-1。正在迁移git至SHA-256将解决此问题,但大多数托管站点(如GitLab和GitHub)尚不支持此功能。使用签名tarball代替签名git提交或git标记还有其他优点,例如。,焦油.gz可以是可确定再现的持久稳定离线存储格式,但是.git(单位:吉特)子目录树或git捆绑包不要提供此属性。

对所有这些进行持续测试对于确保事情不会倒退至关重要。Libntlm的管道定义现在生成生成的libntlm-*.tar.gz数据库tarball和校验和作为构建工件。然后我添加了000可复制性比较校验和并在不匹配时失败的作业。你可以阅读它v1.8工作中的精细输出释放。现在,我们坚持认为Trisquel 11的构建与Ubuntu 22.04相匹配,PureOS 10的构建与Debian 11的构建相匹配,AlmaLinux 8的构建与RockyLinux 8的建立相匹配,而AlmaLinux 9的构建与LockyLinux 9的建设相匹配。正如您可以在管道作业输出中看到的那样,并非所有平台都会导致相同的tarball,但希望这种状态可以随着时间的推移得到改善。还存在部分再现性,其中完整的tarball可以跨两个分布进行再现,但最小tarball不可以,反之亦然。

如果这种工作方式效果很好,我希望也能在其他项目中实施。

你怎么认为?快乐黑客!

走向可复制的最小源代码tarball?在*-src.tar.gz上

在工作期间分析xz后门目前,已经提出了一些改进软件供应链生态系统的想法。其中一些想法是好的,一些想法充其量是无关紧要和无害的,而一些建议显然是坏的。我想尝试将之前讨论过的两个想法形式化,但它们可以被欣赏的背景并不像今天那么清楚。

  1. 可复制的柏油球。其想法是,发布的源tarball应该能够以某种方式独立复制,并且应该不断测试和验证,最好是作为上游项目持续集成系统的一部分(例如GitHub操作或GitLab管道)。虽然名义上这看起来很容易实现,但其中有一些复杂的问题,例如:tarball中的文件使用什么时间戳?我已经提出了这个方面之前。
  2. 在没有生成供应商文件的情况下,最小化源tarball。大多数基于GNU Autoconf/Automake的tarball预先生成了文件,这些文件对于在没有所需依赖项的外来系统上进行引导非常重要。要使引导故事成功,必须支持这种方法。然而,很明显,这种做法会带来巨大的成本和风险。大多数现代GNU/Linux发行版都具有所有必需的依赖项,并且实际上更喜欢从源代码重新构建所有内容。这些预先生成的额外文件给该过程带来了不确定性。

我提出的改进建议是定义新的tarball格式*-src.tar.gz公司至少具有以下属性:

  1. tarball应该允许用户构建项目,这就是所有这些的全部目的。这意味着至少必须包含项目的所有源代码。
  2. tarball应该签名,例如使用PGP或minisign。
  3. tarball应该可以由第三方使用上游的版本控制源和使用修订的指针(例如git标记或git提交)逐位复制。
  4. tarball不应该需要互联网连接来下载东西。
    • 推论:每个外部依赖要么都必须被明确地记录下来(例如,gcc和GnuTLS),要么都包含在tarball中。
    • 观察:这意味着包括所有*.po型 获取文本从版本控制源构建时通常下载的翻译。
  5. tarball应该包含使用尽可能多的外部发布版本化工具从源代码构建项目所需的所有内容。这是目前所缺乏的“最小”财产。
    • 推论:这意味着包括OpenSSL或libz的供应商副本是不可接受的:作为外部项目链接到它们。
    • 开放性问题:非发布的外部工具如何,例如格努利布autoconf存档宏? 这有点微妙:大多数发行版要么只打包一个当前版本的gnulib,要么打包autoconf存档,而不是打包以前的版本。虽然这可能会发生变化,但发行版可以打包gnulib git存储库(直到某些当前版本)和autoconf存档git存储库可提取所需的版本(格努利布的/引导数据库已经通过支持此–gnulib-refdir参数),这通常不到位。
    • 建议的推论:tarball应该包含git子模块的内容,例如gnulib和项目所需的必要Autoconf存档M4宏。
  6. 类似于GNU项目指定的方式/配置界面我们需要一个文档化的界面来引导项目。我建议使用已经很成熟的跑步习惯用法./引导设置包以便以后可以通过./配置。当然,有些项目没有使用autotool./配置接口,也不会遵循这一点,但与autotools竞争的大多数构建系统都有关于如何构建项目的说明,它们应该记录类似的接口,以便引导源tarball进行构建。

如果可以从流行的上游项目中获得实现上述目标的tarball,那么发行版可以更容易地使用它们,而不是包含预生成内容的当前tarball。这样做的好处是构建过程不会被“不必要的”文件污染。我们需要为维护人员开发工具来创建这些tarball,类似于制造距离产生今天的foo-1.2.3.tar.gz(目标.gz)文件夹。

我认为反对这种方法的一个常见论点是:为什么要费心这么做,而只是使用git存档输出?或者避免整个tarball方法,直接转向版本控制的签出,并将上游版本称为git URL和commit标记或idSHA-1坏了,因此信任SHA-1标识符根本不安全。另一个反驳意见是,这以上游维护者为代价优化了打包者的利益:大多数上游维护者不想存储gettext*.po型源代码存储库中的翻译。在维护者和包装者的需求之间进行折衷是有用的,因此*-src.tar.gz公司tarball方法是我们需要解决的间接方法。更新:在我的实验中Libntlm的源代码专用tarballs我实际上使用了git-archive输出。

你怎么认为?

Git-LFS中的Apt存档镜像

我继续努力提高公共apt档案的透明度和信心。我在“Apt存档透明度“我在其中提到债务分配项目正在进行中。债务发行人负责镜像一些公共apt存档的索引文件。我已经意识到,拥有一个可公开审计和保存的apt存储库镜像是实现apt透明工作的核心,因此debdistget项目对我的项目来说比我想象的更为重要。当前我跟踪特里斯克尔,PureOS(纯操作系统),侏儒和他们的上游Ubuntu公司,Debian公司德文

Debdistget下载发布/包/源文件并将其存储在上发布的git存储库中GitLab公司。由于大小限制,它使用两个存储库:一个用于发布/发布中文件(较小)和一个还包括包/源文件(较大)。请参见的存储库示例Trisquel发布文件Trisquel包/源文件。可以在中找到所有分发版的存储库debdistutils的存档GitLab子组

之所以拆分为两个存储库,是因为合并文件的git存储库变得很大,而且我的一些用户只需要发布文件。目前,带有软件包的存储库(现在包含几个月的数据)为9GBUbuntu公司,2.5GB用于特里斯克尔/Debian公司/PureOS(纯操作系统),970MB用于德文和450MB用于侏儒。存储库大小与存档的大小(用于初始导入)以及更新的频率和大小相关。Ubuntu对Apt分阶段更新(这会引发更大的Packages文件修改波动)似乎是其更大的主要原因。

使用大型Git存储库效率很低,GitLab CI/CD作业会产生大量网络流量,反复下载Git存储库。最重的用户是债务差异下载所有发行版包存储库以对发行版之间的包列表执行差异操作的项目。日常工作需要处理80分钟要运行,大部分时间都花在下载档案上。是的,我知道我可以研究运行端缓存,但我不喜欢缓存带来的复杂性。

幸运的是,并非所有的use-case都需要包文件。这个债务清偿项目只需要发布/发布中文件,以便将签名提交给西格斯托尔Sigsum公司透明度日志。这些工作仍然运行得相当快,但看着存储库大小的增长让我担心Debian公司440MB,PureOS(纯操作系统)130MB,Ubuntu公司/德文90MB,特里斯克尔12MB,侏儒2毫巴。在这里,我认为主要的大小相关性是更新频率,而Debian之所以大,是因为我跟踪的波动性不稳定。

因此,我用第一种方法实现了可扩展性。几个月前,我通过丢弃和重置这些档案库来“解决”这个问题。GitLab CI/CD作业又恢复了速度,一切都很好。然而,这意味着放弃宝贵的历史信息。几天前,我再次达到实用性的极限,并开始探索解决此问题的方法。我喜欢将数据存储在git中(它允许轻松集成软件完整性工具,如保密性卫兵和Sigstore,以及git日志提供了一种数据的时间顺序),因此感觉像是放弃了良好的属性,转而使用传统的基于磁盘的数据库方法。所以我开始了解Git-LFS公司并了解到它能够处理多GB的数据这看起来很有希望。

很快,我编写了一个脚本GitLab CI/CD作业增量更新发布/包/源使用git-LFS存储所有文件的git存储库中的文件。存储库大小现在为Ubuntu 650kb,Debian 300kb,Trisquel 50kb,德文250kb,PureOS 172kb侏儒鸟17kb正如所料,作业可以快速克隆git存档:debdistdiff管道运行时间从80分钟减少到10分钟这与存档大小和CPU运行时间之间的关系更为合理。

这些存储库的LFS存储大小为Ubuntu 15GB,Debian 8GB,Trisquel 1.7GB,德福1.1GB,PureOS(纯操作系统)/侏儒4.2亿。这是几天的数据。看起来原生Git比Git-LFS更擅长压缩/重复数据消除:Ubuntu的两天数据总大小已经是15GB,而纯Git的两个月数据总大小为8GB。这可能是GitLab中Git-LFS的次优实现,但我担心这种新方法也很难扩展。在某种程度上,差异是可以理解的,Git-LFS可能存储两个不同的包装文件(Trisquel的每个文件大约为90MB)作为两个90MB文件存储,但本机Git会将其存储为90MB文件的一个压缩版本和一个相对较小的补丁,以将旧文件转换为下一个文件。因此,Git-LFS方法在总体存储大小方面的扩展性出奇地差。不过,原始存储库要小得多,您通常不必提取所有LFS文件。所以这是净赢。

在这项工作中,我一直在思考我的方法与Debian的快照服务。我最终想要的是这两种服务的结合。为了有一个良好的基础来进行透明度工作,我想收集所有发布/包/源文件,以及最终的源代码和二进制文件。虽然从发行版的最新稳定版本开始是有意义的,但这项工作也应该在时间上向后扩展。为了从源代码中重新生成二进制文件,我需要能够安全地找到用于重建的二进制包的早期版本。所以我需要导入所有发布/包/源包从快照到我的存储库。从该服务器检索文件的延迟很慢,因此我无法找到一种高效/并行的方式来下载文件。如果我能完成这项工作,我相信我基于Git-LFS的存储这些文件的新方法将在未来多年内扩展。这还有待观察。也许存储库必须按发行版、体系结构或类似内容进行拆分。

另一个因素是存储成本。虽然基于git-LFS的存储库中包含几年来的文件的git存储库大小可能可以维持,但git-LFS的存储大小肯定不会维持。GitLab似乎对存储库和git-LF中的文件收取相同的费用,而且大约是每100GB 500美元每年。可以设置一个不在GitLab托管的独立Git-LFS后端来服务LFS文件。有人知道适合这种情况的服务器实现吗?我快速看了一下Git-LFS实施列表看起来最合理的方法是设置Gitea-clone福吉乔作为自托管服务器。也许云存储方法a'la S3是未来的发展方向?在GitLab上托管此内容的成本将在以下时间内可控~1TB(5000美元/年)但将其扩展到存储500 TB的数据将意味着每年250万美元这看起来物有所值。

我意识到,最终我想要一个本地的git存储库,其中包含所有apt存档的全部内容,包括它们的二进制和源代码包,并且可以发布。像快照这样的服务(约300TB的数据?)的存储需求目前并不昂贵:20TB的磁盘是500美元一块,因此一个包含36个磁盘的存储机柜大约在500美元左右720TB需要18.000美元使用RAID1意味着360TB,这是一个良好的开端。虽然我听说了~TB大小的Git-LFS存储库,但Git-LFS会扩展到1PB吗?也许拥有数百万个git-LFS指针文件的git存储库的大小将变得无法管理?为了开始使用这种方法,我决定导入Debian的amd64书虫到Git-LFS存储库中。就在附近175GB即使是在GitLab上托管也非常便宜(200GB每年1000美元)。公开此存储库将使编写使用此方法的软件成为可能(例如,移植债务再生产),以确定这是否有用以及是否可以扩展。通过Git-LFS分发apt存储库还可以使用其他有趣的想法来保护数据。考虑配置apt以使用本地文件://指向此git存储库的URL,并使用类似于的方法验证git签出Guix信任git的方法内容或Sigstore的gitsign

天真地推了一下175GB单个git提交中的存档遇到了包大小限制:

remote:fatal:pack超出了允许的最大大小(4.88 GiB)

然而,将提交分解为针对部分存档的较小提交,使得推送整个存档成为可能。以下是创建此存储库的命令:

初始化
git-lfs安装
git lfs track“dists/**”“pool/**”
git添加.gitattributes
git commit-m“添加git-LFS跟踪属性”.gitattributes
time debmirror--method=rsync--host ftp.se.debian.org--root:debian--arch=amd64--source--dist=bookworm,bookworm-updates--section=main--verbose--diff=none--keyring/usr/share/keyrings/debian-archive-keyring.gpg--ignore.git。
git add dists项目
git提交-m“添加”-a
git远程添加源git@gitlab.com:debdistutils/archives/debian/mirror.git
git推送--设置上游源--全部
对于池中的d//;
echo$d;
时间git添加$d;
git commit-m“添加$d”-a
git推送
完成

这个结果存储库大小约为27MB,Git LFS对象存储约为174GB。我认为这种方法可以扩展到为一个版本处理所有架构,但为所有架构的所有版本使用单个git存储库可能会导致git存储库太大(>1GB)。那么,每个版本可能有一个存储库?这些存储库还可以拆分为水池/文件,或者每个体系结构或源的每个版本可能有一个存储库。

最后,我担心如何使用SHA1识别对象。Git和Debian的快照服务目前都在使用SHA1。Git有SHA-256过渡GitLab似乎正在致力于支持基于SHA256的存储库。对于这些概念的长期部署,最好直接使用SHA256标识符。Git-LFS已经使用SHA256,但Git内部使用SHA1,Debian快照服务也是如此。

你怎么认为?快乐黑客!

经典McEliece加入IETF和OpenSSH

我的简化NTRU Prime的早期工作一直在进步。IETF文件SSH中的sntrup761已通过多个处理点。GnuPG的libgcrypt增加了对sntrup761的支持. The对sntrup761的libssh支持正在工作,但合并请求被阻塞,主要是因为没有时间调试为什么回归测试套件在非-sntrup761型与补丁相关的部分。

基础基于格的后量子算法具有一定的不确定性围绕着它,我觉得量子后的故事不仅仅是增加sntrup761型到实现。经典McEliece我已经被提到过几次了,我花了一些时间学习它,并对提议的ISO标准并已发布草案-josefsson-mceliece在IETF中使算法易于IETF社区使用。Classic McEliece的高质量实现已发布为图书馆信仰我一直支持扬·莫伊什的工作Debian的libmcelice包唉,它被卡在了ftp-master NEW队列用于两个月以上的手动审查。先决条件库MBlibcpucycles系列已在Debian中提供。

所有这些文本编写和打包工作都为编写一些代码创造了条件。当我添加对的支持时sntrup761型在里面libssh数据库,我开始熟悉OpenSSH代码库,因此很自然会返回OpenSSH,为Classic McEliece尝试新的SSH KEX。DJB公司建议选择麦塞利6688128并将其与现有的X25519+sntrup761或者用普通的25519平方米而三种算法的混合X25519型,sntrup761型麦塞利6688128对于那些不想失去sntrup761所提供的好处的人来说,这只是一个简单的选择X25519型具有麦塞利6688128.中的关键合路器sntrup761x25519是一个简单的SHA512型我能说的唯一好处是,它的描述和实现都很简单,而且由于它已经部署好了,所以不会引发太多问题。

在拖延了几个月的编码之后,一旦我坐下来工作,只花了几个小时就成功建立了Classic McEliece SSH连接。我想在我开始之前,我的大脑已经把背景中的所有东西都整理好了。要复制它,请在Debian测试环境中尝试以下操作(我使用播客以获得清洁的环境)。

#podman run-it--rm debian:测试-极限apt更新apt dist-upgrade-yapt安装-y wget python3库dbytes-dev libcpucycles-dev gcc生成git autoconf libz-dev光盘~wget-q-O-https://lib.mceliece.org/libmcelice-20230612.tar.gz|焦油xfz-cd libmcelice-20230612/./配置进行安装ldconfig(ldconfig)光盘。。git克隆https://gitlab.com/jas/openssh-portable网址cd openssh-可移植git结帐jas/mcelice自动侦察./configure#verify“libmceliece支持:是”make#CC=“CC-DDEBUG_KEX=1-DDEBUG _KEXDH=1-DDEBUG-KEXECDH=1”

现在您应该有一个支持Classic McEliece的工作SSH客户端和服务器!通过运行验证支持./ssh-Q密钥它应该提到mcelice6688128x25519-sha512@openssh.com

要让它打印大量调试输出,可以删除#角色在最后一行,但不要在生产中使用这样的内置。

您可以按如下方式进行测试:

./ssh-keygen-A#写入/usr/local/etc/ssh-host_。。。#通过运行以下命令设置基于公钥的登录:./ssh-keygen-t rsa-f~/.ssh/id_rsa-P“”cat~/.ssh/id_rsa.pub>~/.ssh/授权密钥adduser—系统sshdmkdir/var/空虽然正确;执行$PWD/sshd-p 2222-f/dev/null;已完成&./ssh-v-p 2222本地主机-oKex算法=mcelice6688128x25519-sha512@openssh.com日期

在客户端上,您应该看到如下输出:

OpenSSH_9.5p1,OpenSSL 3.0.11 2023年9月19日...调试1:SSH2_MSG_KEXINIT已发送调试1:SSH2_MSG_KEXINIT已接收调试1:kex:算法:mcelice6688128x25519-sha512@openssh.comdebug1:kex:主机密钥算法:ssh-ed25519调试1:kex:server->客户端密码:chacha20-poly1305@openssh.comMAC:压缩:无调试1:kex:client->服务器密码:chacha20-poly1305@openssh.comMAC:压缩:无debug1:需要SSH2_MSG_KEX_ECDH_REPLY调试1:收到SSH2_MSG_KEX_ECDH_REPLYdebug1:服务器主机密钥:ssh-ed25519 SHA256:YognhWY7+399J+/V8eAQWmM3UFDLT0dkmoj3pIJ0zXs...debug1:主机“[localhost]:2222”已知,并且与ED25519主机密钥匹配。debug1:在/root/.ssh/known_hosts:1中找到密钥debug1:在134217728个块之后重新密钥调试1:SSH2_MSG_NEWKEYS已发送debug1:需要SSH2_MSG_NEWKEYSdebug1:收到SSH2_MSG_NEWKEYS调试1:在134217728块之后重新键入...调试1:发送命令:date调试1:保证:分叉调试1:permanently_set_uid:0/0环境:USER=根LOGNAME=根HOME=/根路径=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/binMAIL=/var/MAIL/root外壳=/bin/bashSSH_CLIENT=::1 46894 2222SSH_连接=::1 46894::1 2222调试1:client_input_channel_req:channel 0 rtype exit-status回复0调试1:client_input_channel_req:channel 0 rtypeeow@openssh.com回复012月9日星期六22:22:40 UTC 2023调试1:通道0:空闲:客户端会话,通道1传输:发送1048044,接收3500字节,0.0秒每秒字节数:发送23388935.4,接收78108.6debug1:退出状态0

请注意kex:算法:mcelice6688128x25519-sha512@openssh.com输出。

网络带宽使用情况如何?下面是一个完整的SSH客户机连接的比较,例如上面登录、打印日期和注销的连接。普通X25519型大约7kb,X25519型具有sntrup761型大约9kb,并且麦塞利6688128具有X25519型约为1MB。是的,Classic McEliece有很大的密钥,但对于许多环境来说,用于会话建立的1MB数据几乎不引人注目。

./ssh-v-p 2222 localhost-o KexAlgorithms=曲线25519-sha256日期2>&1|grep^已传输传输:发送3028,接收3612字节,0.0秒./ssh-v-p 2222本地主机-oKex算法=sntrup761x25519-sha512@openssh.comdate 2>&1|grep^已转移传输:发送4212,接收4596字节,0.0秒./ssh-v-p 2222本地主机-oKex算法=mcelice6688128x25519-sha512@openssh.comdate 2>&1|grep^已转移已传输:在0.0秒内发送1048044个字节,接收3764个字节

那么会话建立时间如何?

日期;i=0;测试$i-le 100时;这样做/ssh-v-p 2222 localhost-oKexAlgorithms=curve25519-sha256 date>/dev/null 2>&1;i=`expr$i+1 `;完成;日期12月9日星期六22:39:19 UTC 20232023年12月9日星期六22:39:25 UTC#6秒日期;i=0;测试$i-le 100时;这样做/ssh-v-p 2222本地主机-oKex算法=sntrup761x25519-sha512@openssh.com日期>/dev/null 2>&1;i=`expr$i+1 `;完成;日期2023年12月9日星期六22:39:29 UTC12月9日星期六22:39:38 UTC 2023#9秒日期;i=0;测试$i-le 100时;这样做/ssh-v-p 2222本地主机-oKex算法=mcelice6688128x25519-sha512@openssh.com日期>/dev/null 2>&1;i=`expr$i+1 `;完成;日期12月9日星期六22:39:55 UTC 20232023年12月9日星期六22:40:07 UTC#12秒

我从未注意到添加sntrup761型,所以我很确定我也不会注意到这种增长。这一切都在继续我的笔记本电脑运行Trisquel所以对此持谨慎态度,但至少幅度是清楚的。

未来的工作项目包括:

量子后SSH快乐!

更新:将mceliece6688128_keypair调用更改为mcelice6688128f_keypaire(即使用完全兼容的f变量)会导致McEliece的速度与sntrup761型在我的机器上。

2023-12-26年更新:初始IETF文档草案-josefsson-ssh-mceliece-00出版。

简化的NTRU Prime sntrup761加入IETF

这个打开SSH项目增加了对混合动力车的支持优化的NTRU Prime量子密钥后封装方法sntrup761型以加强其基于X25519的违约版本8.5发布于2021-03-03虽然人们对后量子密码有很多讨论,但我的印象是,在过去两年中,它们的实施和部署速度有所放缓。为什么?不管答案是什么,我们都可以尝试协同更改,但奇怪的是,这些算法的IETF文档似乎缺失了一项工作。

在一些早期工作的基础上X25519/X448至SSH,在我花了一天时间阅读OpenSSH和微型SSH了解其工作原理的源代码。虽然我对最终密钥是如何从sntrup761/X25519机密中派生出来的并不十分满意,但这是对串联机密的SHA512调用,我认为应该对构造进行更好的记录,为增加信心或更好的设计铺平道路。此外,重复使用RFC5656第4条structs的规范更糟糕(一个不必要的规范性引用),但实现可能更简单。我已经发表了草案-josefsson-ntruprime-ssh-00在这里。这里的学分是扬·莫伊什TinySSH设计的早期的sntrup4591761x25519-sha512@tinyssh.org2018年,Markus Friedl于2019年将其添加到OpenSSH,Damien Miller于2020年将其更改为sntrup761。有谁能为这部作品的历史增添更多内容吗?

有一次我把我的xml2rfc很容易编写一个文档来描述sntrup761密钥封装机制和X25519密钥协商方法之间以非SSH方式的混合构造。我不知道这项工作是否有用,但它可以作为进一步研究的参考。我出版了草案-josefsson-ntruprim-hybrid-00在这里。

最后,基于Streamlined NTRU Prime的IETF文档怎么样?解释所有的细节,尤其是它背后的数学,将是一项巨大的努力。我开始这样做,但意识到停止解释是一种主观要求。如果我们不能假设读者了解格数学,那么像这样的文档是教授格数学的最佳场所吗?我选择了最简单的方法,只是简单介绍了算法,包括SageMath公司和C参考实现以及测试向量。IETF的观众很少理解数学,所以我认为最好把注意力放在网络和算法接口上。这里的一切都是由Streamlined NTRU Prime团队创建的,我只是稍微修改了一下,希望我不会破坏太多。我现在已经出版了草案-josefsson-ntruprime-streamlined-00在这里。

我维护IETF文件我的ietf-ntruprime GitLab页面,请随时打开合并请求或提出问题以帮助改进它们。

为了对代码的正常工作有信心,我最终准备了一个带有sntrup761的分支对于GNU(全球导航单元)-项目Nettle公司并已提交上游审查。我很不幸不得不理解和执行NIST的DRBG-CTR计算sntrup761已知答案测试,这真是一团糟。为什么确定性随机生成器支持重新播种?为什么它支持非完全熵推导?密钥大小与块大小的混淆是什么?可选参数是什么?有多个算法描述是什么?幸运的是我能够提取一个最小但有效的实现这很容易阅读。我找不到DRBG-CTR测试向量,有人吗?是否有人拥有不使用DRBG-CTR的sntrup761测试向量?关于发布使用随机数据的算法的已知答案测试的最后一点思考:测试向量在实现算法的不同方法上是否稳定?只要考虑一些优化,将一个随机抽取调用移动到另一个调用之前,那么输出不会有所不同吗?还有其他方法来验证实现的正确性吗?

一如既往,快乐黑客!