<div dir="ltr"><div>Apologies if what I'm about to say seems tangential... hopefully it provides historical context that is useful to the discussion at hand.</div><div><br></div><div>=====</div><div><br></div><div>Remember that code signing was first implemented for apps that were published on the iOS App Store. This was very quickly (maybe even simultaneously?) adopted for the Mac App Store. Since the code signing was generally seen as "a good thing"™ in terms of security, Apple has since rolled it out nearly everywhere. Some people, including me, have seen this as just one more indication of the "iOS-ification" of the Mac operating system, a process which began when they renamed Mac OS X to macOS. Another example of the "iOS-ification" of macOS is where, starting in Catalina, and then in Big Sur, Apple moved the System volume to a partition that is mounted read-only, and then also sealed that volume into a Signed System Volume (SSV). (See? there's that word again... "Signed".) This structure of a read-only and signed volume that contains the entire operating system is the way that iOS has been structured for a very long time (maybe even since the beginning). Getting around this structure, and turning the volume where iOS resides into one that is read-write, is one part of what is generally referred to as "jailbreaking" iOS.</div><div><br></div><div>Apple's app stores are highly centralized, being 100% hosted, administered, and controlled by a single entity. Thus, they have a need for code signing, so that they can use the code-signing keys as a mechanism to control whether or not a third-party developer's app is allowed to be visible to the public through their (first party) app stores. On the other hand, MacPorts is much more similarly structured <font color="#202122" face="sans-serif"><span style="font-size:14px"><i>—</i></span></font> in terms of infrastructure, governance, and philosophy <font color="#202122" face="sans-serif"><span style="font-size:14px"><i>—</i></span></font> to a package manager on Linux, and is highly decentralized. This sentiment appears to be echoed in Wikipedia's article on code signing (<a href="https://en.wikipedia.org/wiki/Code_signing" target="_blank">https://en.wikipedia.org/wiki/Code_signing</a>), in the last paragraph of the section entitled "Providing security". In particular, I would like to point out the citation at the end of that paragraph, which links to a discussion of apt-secure on the Debian wiki (<a href="https://wiki.debian.org/SecureApt" target="_blank">https://wiki.debian.org/SecureApt</a>). If you read through the Debian wiki page, you will see that, circa 2003-2005, when Debian moved away from simply using MD5 checksums, they decided to go the route of using public key cryptography in the form of GPG keys, instead of going down the road of code signing the way that Apple has implemented it.</div><div><br></div><div>=====</div><div><br></div><div><div dir="ltr" class="gmail_attr">On Tue, Mar 22, 2022 at 12:02 AM Joshua Root <<a href="mailto:jmr@macports.org">jmr@macports.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">On 2022-3-22 12:20 , Ryan Schmidt wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">Could MacPorts codesign everything installed by ports? If so, should we? What benefits would that bring? How would we do it?</blockquote><br>We could ad-hoc codesign everything, which would not improve security at<span class="gmail-Apple-converted-space"> </span>all, but would get GateKeeper to ease up a bit on restrictions on<span class="gmail-Apple-converted-space"> </span>incoming network connections and the like.</blockquote></div><div><br></div><div>If ad-hoc code-signing everything would not involve the need for anyone, either on the MacPorts side or the user side, to have a Developer ID, then it seems like this would generally be a good idea. Reducing the number of interactions with GateKeeper would help reduce user confusion. (Does anyone remember the frequency of the UAC prompts in Windows Vista?)</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">Doing actual useful codesigning would require a few things:<br>1. A Developer ID for the project. I'm happy to sign the installers with<span class="gmail-Apple-converted-space"> </span>my personal Developer ID because I build them myself and I am familiar<span class="gmail-Apple-converted-space"> </span>with the code contained in them. I would not sign arbitrary third party<span class="gmail-Apple-converted-space"> </span>code.<br>2. A Developer ID for every user who needs to install any ports that are<span class="gmail-Apple-converted-space"> </span>not available as binaries. We obviously can't distribute our secret key<span class="gmail-Apple-converted-space"> </span>to the public, so anything built locally needs to be signed locally,<span class="gmail-Apple-converted-space"> </span>with a locally configured identity.<br></blockquote><div><br></div><div>This seems like it would be adding a huge burden onto people who simply want to use MacPorts.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">3. A willingness to endorse every binary we ship by putting our<span class="gmail-Apple-converted-space"> </span>signature on it.<br></blockquote><div><br></div><div>Does MacPorts, as a group of developers, really want to be in the business of endorsing every binary that's available in our catalog of nearly 30,000 packages? The various Linux package management systems certainly don't make any such claims or guarantees, and in fact explicitly state the opposite. And even though Apple also has text stating that they don't "endorse" any apps in their app stores, the fact of the matter is that they do still take it upon themselves to police the apps (and the developers) on their app stores. This also relates back to point #1, where the MacPorts Developer ID would be getting used to arbitrarily sign third-party code.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">4. A plan for what to do if we inadvertently ship malware and our<span class="gmail-Apple-converted-space"> </span>Developer ID certificate is revoked. AIUI, that would make it impossible<span class="gmail-Apple-converted-space"> </span>to run anything signed with the existing certificate if GateKeeper is<span class="gmail-Apple-converted-space"> </span>enabled. Everything would presumably have to be re-signed and reinstalled.<br></blockquote><div><br></div><div>I believe Josh is correct. A certificate revocation means having to start over from scratch and "re-publishing" everything with a new certificate. This is also what happens when a developer's certificate gets revoked on any of Apple's app stores.</div><div><br></div><div>=====</div><div><br></div><div>Finally, I'm of the belief that code signing would not prevent, nor was it designed to prevent, malicious or buggy code from making its way into distributed software. It didn't prevent the Log4j bug/vulnerability, and it wouldn't have prevented the node-ipc situation from occurring. In my opinion, it's not, nor should it be, our job to guarantee that we are providing bug-free and non-malicious software from upstream third-party sources. Our current merge review process already implements many of the best practices used by open-source projects to try to guard against such software from making it from upstream all the way to being released by our distribution network. However, I believe that it IS our role to strive to provide bug-free and secure first-party software, i.e. MacPorts base, MacPorts legacy support, Portfiles, and the other pieces of code that are directly released by the group of volunteers that make up "The MacPorts Project"™.</div><div><br></div><div>I'm only a package maintainer, and so I don't expect my opinion to have much weight on final decisions, but I'm of the opinion that the current situation should stay as it is: we release a MacPorts installer that has been code signed, but we should not be code signing any of the ports using a Developer ID certificate. Ad hoc signing of ports might be useful, as long as it doesn't involve the need for a Developer ID certificate.</div><br clear="all"><div><div dir="ltr" data-smartmail="gmail_signature"><div dir="ltr"><div>-- </div><div>Jason Liu</div></div></div></div><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Mar 21, 2022 at 9:21 PM Ryan Schmidt <<a href="mailto:ryandesign@macports.org" target="_blank">ryandesign@macports.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">Sorry, this got long.<br>
<br>
I want to move a discussion to the macports-dev list that began with a user's question to macports-mgr. This user ran a third-party utility which reported that some files installed by MacPorts were not codesigned and asked if it was a concern.<br>
<br>
I replied that the files installed by the MacPorts installer are codesigned but that MacPorts predates the existence of codesigning and nobody has yet added code to MacPorts that arranges for files installed by ports to be codesigned. Individual ports might codesign their files if that's how their build system was written. On Apple Silicon all (code?) files must be codesigned and the linker (?) takes care of ad-hoc codesigning the files automatically. I also said I wasn't really clear on what purpose codesigning serves; MacPorts and macOS got by fine without it for years.<br>
<br>
The user replied asking if codesigning might reduce the risk of compromised open source packages, referencing this incident in which the developer of node-ipc deliberately released a version containing malicious code:<br>
<br>
<a href="https://www.schneier.com/blog/archives/2022/03/developer-sabotages-open-source-software-package.html" rel="noreferrer" target="_blank">https://www.schneier.com/blog/archives/2022/03/developer-sabotages-open-source-software-package.html</a><br>
<br>
This is a hypothetical question since node-ipc is not in MacPorts and as far as I know a similar situation has not happened with any software that we do have in MacPorts. And since then node-ipc appears to have been forked by a different developer and a new non-malicious version has been released.<br>
<br>
I felt that the broader MacPorts developer community might care to hear a reply to this or to discuss whether and how we should modify MacPorts base to codesign everything installed by ports.<br>
<br>
~<br>
<br>
Certainly the situation with node-ipc was undesirable but I don't see how MacPorts codesigning its files would solve it. I'll talk about that in a minute. First let me discuss what safeguards MacPorts already contains.<br>
<br>
MacPorts ports already fetch specific maintainer-tested versions of the source code. If a developer releases a new version, nothing changes in MacPorts until a MacPorts contributor updates the Portfile to use that new version. Before doing so the MacPorts contributor is expected to verify that the port at least compiles on one macOS version; that the port's test phase runs, if the port has one; that "port lint" doesn't show any easily fixable mistakes; and ideally that some basic functionality of the installed files works. If the port has subports, this applies to all subports as well.<br>
<br>
MacPorts already checksums distfiles. The MacPorts master build server saves a copy of distfiles (assuming the checksum matches at the time) and these are mirrored on servers around the world. If a developer replaces a distfile on their server with something else (maliciously or not), MacPorts will not install the port using that distfile; it will issue a checksum mismatch error and tell the user how to report it to us. Or MacPorts might download the previous "good" file from a MacPorts mirror, bypassing the developer's new replacement file. When we notice such a "stealth update" has occurred, proper procedure is to compare the old and new file to see whether something malicious has happened so that we can decide whether we should modify the port to use the new file or to bypass it. (We might also bypass a new developer distfile if it contains no relevant differences from the old one.)<br>
<br>
Ports that fetch their sources from a revision control system do not enjoy the protection of checksums. Although ports that fetch source from a revision control system specify which tag or commit hash to fetch, it is conceivable that a developer with sufficient access to that repository could delete an old tag and replace it with a new tag of the same name that contains different software. This is one of the reasons why we recommend ports fetch using distfiles, and the vast majority do. We might consider recommending that ports that fetch directly from a git repository (fetch.type git) never use a tag, and always use the commit hash corresponding to that tag, since replacing the contents of the repository while keeping the same sha1 hash is, as far as I know, still impossible in the general case. (Yes, it is possible to engineer a sha1 collision, but only if you can carefully control both the old and new files. Generating a sha1 collision against some existing old file is a very different matter.)<br>
<br>
Some ports' build systems fetch additional files from the Internet at build time. This too is discouraged in MacPorts. Who knows whether such build systems download specific versions of those files or whether their integrity is verified in any way. This represents another avenue by which unverified files (which might have been replaced with malicious versions) could make their way into a build of a port. And if that one server that the build system is programmed to download from is down, the installation fails. Ports should specify all their needed files as distfiles and allow MacPorts to be in charge of downloading and mirroring and checksumming them. To my annoyance, developers are increasingly adopting build systems that download their own files. The difficulties that this poses for verifying the integrity of the final product should be communicated to those developers by interested MacPorts contributors. Developers should continue to employ the time-tested practice of offering a single distfile that contains all the code needed to build the project (excluding external libraries).<br>
<br>
For most ports, most users can receive binary archives from us and do not need to obtain the source code and compile it themselves. These archives are produced on build servers that I control; nobody else has access or could compromise them (except for the Apple Silicon build machine which is colocated in a reputable data center). All build machines transfer the archives they build to my master build server which signs them with our private key. Nobody has access to this private key except me at the moment. Prior to 2017 when our build servers were hosted by Apple, Apple server administrators had access to the private key. Just like with the distfiles, the archives and their signatures are mirrored on servers around the world. When MacPorts on a user's computer downloads a binary archive it verifies the signature using our public key before installing it.<br>
<br>
So nobody could replace distfiles or binary archives on any server without error messages appearing that would stop an installation.<br>
<br>
The ports tree that users get from our rsync server as a tarball is also signed with our private key and verified with our public key, so a malicious mirror operator could not, for example, replace Portfile code without verification of the tarball failing.<br>
<br>
~<br>
<br>
That brings us to node-ipc. On March 7 a developer committed this malicious change to node-ipc:<br>
<br>
<a href="https://github.com/node-ipc/node-ipc/commit/847047cf7f81ab08352038b2204f0e7633449580#diff-c2dd3b497ae886cfb8f5bf8c66c649fc2ae4afaa6660d9bbf3105d69884679c6" rel="noreferrer" target="_blank">https://github.com/node-ipc/node-ipc/commit/847047cf7f81ab08352038b2204f0e7633449580#diff-c2dd3b497ae886cfb8f5bf8c66c649fc2ae4afaa6660d9bbf3105d69884679c6</a><br>
<br>
and version 10.1.1 was released shortly thereafter. We don't have node-ipc in MacPorts but if we did and if someone noticed that this new version was available, they would have updated the Portfile's version line, fetched the new distfile, updated the Portfile's checksums to match it, and tried to install the port. They might have run the test suite and/or verified the basic functionality of the files that got installed. Then they would have committed the update. They would most likely not have known about or noticed the malicious code since it was programmed to take effect only under certain conditions.<br>
<br>
So now the checksums of the malicious distfile would be in MacPorts. MacPorts servers would mirror the malicious distfile. MacPorts build servers would build it and create binary archives of the malicious version which would be signed with our public key. If MacPorts contained any code that codesigns files, it would codesign the malicious files before they went into the binary archives. So I don't see how the addition of codesigning to MacPorts would prevent malicious code from getting into MacPorts via this method.<br>
<br>
It is not MacPorts policy to require contributors to examine every upstream change between the old software version and the new one in order to verify that it is free from malware or for any other purpose. I don't think anybody could be expected to do that. I would guess most MacPorts contributors are not familiar with the upstream code of the projects they maintain, may not even be proficient in the programming language they're written in, and might not be able to recognize a malicious change if one were there. Some projects do not even have public source code repositories so you couldn't review each individual commit and would have to examine a single aggregate diff between an old and new version which could be tens or hundreds of thousands of lines long; asking a MacPorts contributor to ascertain whether such a diff contains malicious changes seems like an impossibility. (node-ipc does have a public repository, and it is a small project and the diff between versions 10.1.0 and 10.1.1 was under 500 lines, so a review of that change would have been possible.)<br>
<br>
It is not even our policy that contributors must read the NEWS or CHANGELOG files to see what changed, though I sometimes do this as it helps me discover things like if dependencies need to be changed. This malicious change in node-ipc was obfuscated so the code's purpose could not be seen at a glance. The change was in a JavaScript file and JavaScript files are often "minified" (obfuscated in order to reduce their size for lower bandwidth use) so this might not have been seen as suspicious. The description of the change in the commit message did not seem suspicious, and that project does not maintain NEWS or CHANGELOG files, nor would I imagine that a malicious change would be described as such in them if it did. Seems like more and more projects are ditching NEWS and CHANGELOG files. Some developers suggest reading the commit messages between versions as a substitute, which strikes me as inadequate.<br>
<br>
~<br>
<br>
So what can we do to combat malicious code in upstream projects? Remove it as soon as we learn about it. Revert the port back to the previous good version. Or patch out the malicious code. Write a comment in the port advising future contributors to exercise special care when updating it and to actually check the differences for potential malware. If the software developer is an ongoing threat consider removing the port from MacPorts or switching to a fork by a different developer if that exists.<br>
<br>
I'll also say that all contributions to MacPorts from the public are reviewed by trusted contributors. Proposed changes are submitted either as an attachment in a Trac ticket or as a pull request on GitHub, where potential problems can be identified and fixed prior to those changes being merged into the repository and becoming available to everyone else. Pull requests automatically run continuous integration. Currently we check that the port builds on two macOS versions and run it through "port lint". Additional checks could be added. For example, if there is a tool that checks a directory of files for known malware, we could run that.<br>
<br>
Once the changes land in the repository, an email of the changes is sent to the macports-changes mailing list where I and others review them again. All MacPorts contributors are encouraged to subscribe to the macports-changes mailing list to see what's changing in MacPorts, to learn common Portfile development techniques, and to help spot and fix mistakes before they are noticed by our users. This review process would not have caught an update of a hypothetical node-ipc port to 10.1.1 since the bad code was not in MacPorts but in the upstream project, but it constantly helps uncover and fix other issues.<br>
<br>
~<br>
<br>
Could MacPorts codesign everything installed by ports? If so, should we? What benefits would that bring? How would we do it?<br>
<br>
<br>
</blockquote></div>