Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The FontValidator binary can’t be code signed on macOS #53

Closed
schriftgestalt opened this issue Jan 10, 2020 · 39 comments
Closed

The FontValidator binary can’t be code signed on macOS #53

schriftgestalt opened this issue Jan 10, 2020 · 39 comments

Comments

@schriftgestalt
Copy link

@schriftgestalt schriftgestalt commented Jan 10, 2020

To be able to update the macUI for MacOS 10.15, I need to code sign the binary. But I get errors as described here:
https://stackoverflow.com/a/48336883/5329717

@HinTak
Copy link
Owner

@HinTak HinTak commented Jan 10, 2020

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Jan 10, 2020

There is indeed an upstream bug : https://xamarin.github.io/bugzilla-archives/52/52443/bug.html

I'll see if I can find any more recent work to fix that.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Mar 25, 2020

@schriftgestalt can you have a look at the binary under the codesign-fix branch ? If it works, I'll just pull it into master, and do the future binaries the same way. FontVal is kind of in need of an update anyway.

I have written a python script using macholib, based on the advice at the bottom of https://github.com/pyinstaller/pyinstaller/wiki/Recipe-OSX-Code-Signing , to work-around the upstream bug mono/mono#17881 .

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Apr 2, 2020

@schriftgestalt I have pulled the codesign fix branch into master, and will be deleting that branch. Would appreciate if you give it a try sometimes.

Loading

@threeseat
Copy link

@threeseat threeseat commented Apr 4, 2020

I was able to codesign the new binary

$ codesign --force --strict --sign 210065C8E28654BEEA636A5D030A09E72CEE178F -o runtime FontValidator
FontValidator: replacing existing signature`
FontValidator: signed Mach-O thin (x86_64) [FontValidator]
$ codesign --verify FontValidator
FontValidator: valid on disk
FontValidator: satisfies its Designated Requirement

Loading

@schriftgestalt
Copy link
Author

@schriftgestalt schriftgestalt commented Apr 4, 2020

It works now. I’m preparing a new version.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Apr 4, 2020

@schriftgestalt. @threeseat : Good to know. Thanks a lot. Please give me a pull of your updates.

Loading

@threeseat
Copy link

@threeseat threeseat commented Apr 5, 2020

@schriftgestalt : The binary included in the build and in the source tree is the Mono-dependent one, not the stand-alone executable.

@HinTak : Your signable binary was version 2.1.1. Do you plan to update it to a more recent release?

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Apr 5, 2020

@threeseat apologies, you are right. Fixed now. Actually I like to do a 2.1.5 soon, but it will be a bit (a few weeks at least?).

Loading

@threeseat
Copy link

@threeseat threeseat commented Apr 6, 2020

I wasn't able to run version 7 of the Mac app either. When I try, I get a popup window with the error message Something went wrong: Unknown command line option: '-file'

When I try to directly run the FontValidator command-line executable, whether in the app bundle's Resources directory or in the MacUI/FontValidator folder, I get the error message Usage is: mono [options] program [program-options]

I misdiagnosed the problem with version 6 of the Mac app -- the trouble arises from codesigning the Mono executable:

  • I'm able to run the 2.1.4 executable in the MacUI/FontValidator folder in commit 0ec0b4e without problem.
  • If I codesign that executable, however, it no longer runs, and I get the same mono error message as above.

I'm able to locally build and run the app with the unsigned command-line binary. That might be just because I'm building and running it locally. @schriftgestalt, Can a working app be distributed without codesigning the binary?

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Apr 7, 2020

Oh dear. I 'll have a look what is broken. Likely an upstream issue.

Loading

@threeseat
Copy link

@threeseat threeseat commented Apr 7, 2020

It appears related to mono/mono#18826

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Apr 7, 2020

@threeseat thanks for looking it up. I thought it might be something like that - I 'll see if I can fix it somehow.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Apr 7, 2020

I have looked at the actual code, it is not hard, in principle, to fix - mono looks a the end of itself to find the special token, the signature block appends, so things break. It mostly needs to have another go to find the special token before the signature. I am looking at how variable it is - if the worse come to the worse, you can always scan barbarically backwards, but I'd rather not do that. So this means writing a small header parser to fins the special token, xmonkeyslovemagic.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Apr 8, 2020

I posted a patch to mono/mono#18826 - I'll need to build mono itself (at least the loader part) for testing.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Apr 16, 2020

@schriftgestalt @threeseat It has taken a while - building a patched mono, down a rabbit hole of some compiler issues - anyway, please try to sign the top of the master branch a try again, and see if that works now, and let me know either way, Btw, this needs os x 10.13 onwards - I hope you (and your typical users...) are up to date enough.

Loading

@threeseat
Copy link

@threeseat threeseat commented Apr 27, 2020

I was able to codesign the binary at MacUI/FontValidator/FontValidator/FontValidator, but because the included FreeType dylib is unsigned, I had to disable library validation for the hardened runtime.

I've created a pull request (#61) that has the library codesigned with an ad hoc signature, in case that resolves the issue.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Apr 27, 2020

Thanks for doing this. Oh, that's a lot of pain! How does it work /difference between your signing and @schriftgestalt 's? I'll pull it in and update the binary. The repo is getting slightly bloated with binaries :-).

Loading

@schriftgestalt
Copy link
Author

@schriftgestalt schriftgestalt commented Apr 27, 2020

I codesign everthing manually beforehand, including the libs. The stuff in my repo should be signed correctly. But it is with my signature…

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Apr 27, 2020

The library is at bin/Darwin/libfreetype.6.dylib, which is baked into MacUI/FontValidator/FontValidator/FontValidator . It is still a two-step process, sign the lib, bake it into the binary, then sign the binary... I am just wondering if mac os wants the same signing person for the whole thing. Anyway, I'll bake it in to see if it works.

Loading

@schriftgestalt
Copy link
Author

@schriftgestalt schriftgestalt commented Apr 27, 2020

If the libraries are backed into the binary, then they don’t need to be code signed.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Apr 27, 2020

It is a bit more complicated than that. The way the binary works, is that at the beginning of its running, it looks at itself and extract the baked-in library to a temporary directory, then, load it. It was made to work that way with mono 4.8, when apple started to stop binaries loading libraries from non-system places. anyway, if signing twice works (even if signing by two different people), then that's tedious but okay.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Apr 28, 2020

@schriftgestalt @threeseat - okay, I updated the binary. Georg, if you are worried about giving/shipping libraries signed by somebody else - I have made some changes to my python script which examines (and modifies ) mac os x binaries to look at libfreetype before and after. It is slightly more complicated than the mono binary (which is single-arch, for 64-bit only), as i built the libfreetype bi-arch, as a fat binary. The signing process basically appends a signature block to the 32-bit section, and another signature block to the 64-bit section; The two sections are both padded to 4k's. So the difference before and after, are the two separate sections with or without the two new signature blocks, plus or minus padding, plus adjustments about locations in the three headers (the overall fat binary header, and the 32-bit/64-bit header). The padding itself is a bit complicated - sections in fat binaries are padded to 4k's, while signatures are appended after padded to 16-byte (or 8, not sure, I have only seen a few). i.e. before

Let's say fat needs to pad to 8, but signature appends after pad to 4:

before:
xxxxxxxx yyyyyyyy yyyyyyyy y******* zzzzzzzz zzzzzzzz zz******
after:
Xxxxxxxx Yyyyyyyy yyyyyyyy y***ssss ss****** Zzzzzzzz zzzzzzzz zz**SSSS SSS*****

Where x=fat header, y=32-bit section, z=64-bit section, *=padding, s and S the two signatures. X, Y, Z=modified.

Anyway, I am happy that the bulk of the code section (y and z) are the same, after signing. @schriftgestalt

Loading

@schriftgestalt
Copy link
Author

@schriftgestalt schriftgestalt commented Apr 28, 2020

For the UI app, it would be simpler to put the libraries into the bundle as load them as usual. That should be saver then the packing/unpacking.

Or build static libs and link them in directly (I do that in Glyphs so I know that it works).

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented May 14, 2020

@schriftgestalt how are you with the new release? I have a few other things to do but those don't affect mac os x. So if the current binary (which has an embedded freetype signed by @threeseat ) can be signed by you, that's the next release.

Loading

@schriftgestalt
Copy link
Author

@schriftgestalt schriftgestalt commented May 14, 2020

I’m very busy right now. I’ll try to have a look tomorrow.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented May 14, 2020

@schriftgestalt that's okay - whenever you can. Let me know either way - it works or not.

Loading

@schriftgestalt
Copy link
Author

@schriftgestalt schriftgestalt commented Jun 14, 2020

It seems that the included libs need to be signed by me, too. I signed it, so now you need to repackaged the binary again.

But I would prefer that the dylibs would not be copied into the binary. Either link it statically, or just keep them next to the binary.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Jun 14, 2020

Thanks a lot. I'll do it soon.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Jun 14, 2020

@schriftgestalt Thanks for all the trouble. I have updated the binary now; if you could check that it works, sometimes soon, with a new GUI release, I'll put it up on the release page. We can then close this.

Let me try to explain the situation a bit about libfreetype. There are both technical and political reasons that the freetype customized code aren't going into freetype main any time soon; and in any case, freetype isn't a standard system component on Mac OS X anyway, so we'll always need our own copy. Many Mac users however, will have a copy of some version of libfreeype under /usr/local via homebrew, for example, for various reasons. As you might remember, the earlier releases uses
DYLD_LIBRARY_PATH to specify where to find that our specific copy of freetype.

Several versions of Mac OS X ago, Apple announced that playing with DYLD_LIBRARY_PATH to re-direct library look-up are not recommended and should not be expected to work in coming releases; also it is neater to have just one visible piece, rather than 3+ loose pieces (a central binary, a bundled library, and a launch script which launches the binary with directions to find where the library is). So the mono people came up with the idea that the mono runtime would look for extra-stuff appended into the end of its own binary, unpacks them on launch, and open each of those pieces explicitly. This is quite neat, as everything is all in one binary.

With the requirement of code-signing, this idea is broken in two ways:

  • before signing, the signing tool checks that the binary is well-formed. The extra stuff appended to the mono runtime binary does not bother the os binary launcher, but confuses the signing tool . This is mono/mono#17881 . I wrote a python script to edit the binary slightly (as in the next paragraph) to work around this. It is not a proper fix, but get the job done.

  • if you manage to sign the binary (after modifying the binary slightly, by claiming all the extra stuff appended is just part of static string data compiled in as in the C/C++/obj-C code), the digital signature itself is appended to the binary itself. This confuses the mono runtime, which tries to find the extra stuff by scanning itself from the end. This is mono/mono#18826 . I have submitted an fix to give the mono runtime enough understanding of the digital signature to skip over it when scannning backwards; it has not been accepted yet, but this is basically https://github.com/HinTak/mono-modification/ is.

I have given issues surround this a lot of thoughts, and here are what I think we'd do in the long term:

  • In the Mac GUI app usage scenario, going back to the binary + library separation. It is possible to tell any binaries within to preferably look for libraries under ../Resources/ and or in a relative bundled location? This may or may not be the same as the mechanism of using install_name_tool to re-direct library look-up (there are noise from Apple saying this will break too...). How reliable is this and do you have any more technical details about library look-up within the same bundle works?

  • I'd like to split the repository into two, and give you full access to the MacUI part. This is mainly because of the large binaries / releases which non-mac users are not interested, and it is better organized that way; as the Mac UI part really only need two binary pieces from main, (and perhaps periodic sync of some of the html docs).

  • for mac users who are more command-line centric, I'd still like the all-in-one binary to work. How broken is the current situation - i.e. unsigned command-line binary with unsigned library? If you run it on the command line, do you still see, e.g. prompt to go ahead launching unsigned binaries? Besides code-signing, I also read up about issues with notorization, which seems to be extra trouble in addition to code-signing. I am not a mac user, so any experience you can share is nice.

Loading

@schriftgestalt
Copy link
Author

@schriftgestalt schriftgestalt commented Jun 15, 2020

This article describes how to specify the position of linked libraries: https://wincent.com/wiki/@executable_path,_@load_path_and_@rpath

This will not go away as it will break every single app. Can you point me to the deprecation warning you where speaking about?

And I still don’t understand why you don’t use static linking? That would properly include the library into the executable.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Jun 15, 2020

This, for example: googlefonts/fontbakery#2801

Static linking isn't quite applicable - remember much of FontVal is in C# and compiled to a form of byte code, then executed by a byte-code runtime. It is not obvious only because the runtime is built into the OS on windows, called dotnet. So some form of dynamic loading is always there, because part of it is not compiled into machine code. (or I might need to hack at mono itself some more...).

Loading

@schriftgestalt
Copy link
Author

@schriftgestalt schriftgestalt commented Jun 15, 2020

The example doesn't say anything about something being deprecated. I don’t fully understand what's going on but this is a misconfiguration rather than a technical limitation. Actually it might be a similar problem as we have with the fontVal binary.

But to launch, some part of the binary need to be Mach-O (that then loads the runtime). And that should be able to link to the lib.

All this copying of libraries into the temp folder looks like a massive security risk.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Jun 15, 2020

There are many references to "System Integrity Protection breaks DYLD_LIBRARY_PATH" on a Internet search.

Yes, being able to load library from a non-system location is considered a security risk - Apple would like you to sign binaries and do notorization (upload your binary to be certified by them, as far as I understand it).

I am not saying it is not - but as this is Microsoft tech, you inherit some of Microsoft's lax thinking... And it being 20-year old tech too... So yeah, I like Fontval to have a more apple-centric design and a modern one too, but it is about 20-years too late :-(.

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Jun 15, 2020

To this day, you can still get a Microsoft app to preferably load a custom dll of the same name as a system one, just by copying your custom dll into the same folder. Obviously very different mind set...

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Jun 16, 2020

@schriftgestalt I have tagged 2.1.6 with a small update to get the FeatureParams things better as discussed on the opentype list. If you haven't made a new build yet, please use that sync to that.

Loading

@schriftgestalt
Copy link
Author

@schriftgestalt schriftgestalt commented Jun 16, 2020

Loading

@HinTak
Copy link
Owner

@HinTak HinTak commented Jun 25, 2020

@schriftgestalt since it had been out for a week or so and there are about 50 downloads and I have not heard otherwise, this can close... I'd like to split the mac guI part out as 'FontVal-MacGUI' or something similar - any suggestions? Basically I am planning to replace the directory with a submodule, and moving the GUI part to the bottom of its own directory and repo. Any suggestions for the name?

Loading

@HinTak HinTak closed this Jun 25, 2020
@schriftgestalt
Copy link
Author

@schriftgestalt schriftgestalt commented Jun 25, 2020

‘FontVal-MacGUI’ looks good.

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants