I have a .app that is quarantined. But I am super confused how can my .app be properly codesigned and yet still be quarantined by Apple? I have an app called iTest.app that I downloaded from my server and made sure that it was codesigned correctly but yet it is still quarantined? I thought that having a valid code signature was the whole point of getting past Gatekeeper?
MyMac-7:Downloads user$ ls -l# iTest.app
total 0
drwxr-xr-x# 7 user staff 238 Apr 21 08:05 Contents
com.apple.quarantine 67
MyiMac-7:Downloads user$ codesign --verify --deep --strict -vvvvvvv
iTest.app
iTest.app: valid on disk
iTest.app: satisfies its Designated Requirement
MyiMac-7:Downloads user$ spctl -a -t exec -vvvvvvv iTest.app
iTest.app: accepted
source=Developer ID
origin=Developer ID Application: myID
Related
I have an app bundle containing a cli tool and a dylib. For testing I am calling the cli tool in Terminal (iTerm2):
DYLD_INSERT_LIBRARIES=./libwebsockets.14.dylib THNUCLNT_SVC="private" ./thnuclnt -v
dyld: Library not loaded: #rpath/libwebsockets.14.dylib
Referenced from: /Users/rwelz/Downloads/ezeep Connector.app/Contents/Resources/thnuclnt/thnuclnt/x86_64-darwin/./thnuclnt
Reason: image not found
Abort trap: 6
When I remove the signature from cli tool, everything works fine:
codesign --remove-signature thnuclnt
DYLD_INSERT_LIBRARIES=./libwebsockets.14.dylib THNUCLNT_SVC="private" ./thnuclnt -v
ThinPrint Client Mac Version 7.6.10.1, (c) 2007-2019 ThinPrint GmbH
removing signature from libwebsockets.14.dylib has no effect at all.
I know that the cli tool is using dlopen to load the dylib. But I have no code for the cli tool nor for the libwebsockets.dylib since these are programmed by a colleague of mine. I am only responsible for putting everything together in the app bundle. But everything is build on our build server - so everything uses the same certificate for code signing.
I expect my cli tool to load libwebsockets.dylib and execute and output the same as if it had no signature.
What is changing on the cli tool when codesign is applied? What is going on here?
Many thanks for your valuable help
regards,
Robert
PS.:
libwebsockets.14.dylib and tnuclnt reside in the same directory inside the resource folder of the app:
~/Downloads/my_supersecret.app/Contents/Resources/thnuclnt/thnuclnt/x86_64-darwin/] $ ls -l
total 3368
-rwxr-xr-x 1 rwelz staff 268K Sep 25 11:35 libwebsockets.14.dylib
-rwxr-xr-x 1 rwelz staff 321K Sep 25 11:35 thnuclnt
I am trying to use productsign to sign a XAR archive containing 2 pkg files created using productbuild . The xar tool is creating the file correctly, but I think the signing is corrupting the content, even though the file obtained is signed.
Some relevant command outputs below (I replaced the sensitive information with INFO):
$ ls .
file1.pkg file2.pkg
$
$ xar -cf '../_file.xar' .
$
$ cd ..
$ /usr/bin/productsign --sign 'Developer ID Installer: INFO' '_file.xar' 'file.xar'
productsign: using timestamp authority for signature
productsign: signing product with identity "Developer ID Installer: INFO" from keychain /Users/INFO/Library/Keychains/login.keychain
productsign: adding certificate "Developer ID Certification Authority"
productsign: adding certificate "Apple Root CA"
productsign: Wrote signed product archive to file.xar
$
$ /usr/sbin/pkgutil --check-signature 'file.xar'
Package "file.xar":
Status: signed by a certificate trusted by Mac OS X
Certificate Chain:
1. Developer ID Installer: INFO
SHA1 fingerprint: INFO
-----------------------------------------------------------------------------
2. Developer ID Certification Authority
SHA1 fingerprint: INFO
-----------------------------------------------------------------------------
3. Apple Root CA
SHA1 fingerprint: INFO
$ file file.xar
file.xar: xar archive - version 1
$
$ xar -xf file.xar -D /tmp
Error while extracting archive:(file1.pkg): Error decompressing file
$
Is the productsign command intended to work in some other way? I don't understand what is wrong with my approach.
After some testing, I found out xar is using relative paths inside the archive, so in my case there was a problem because I used "../" inside a path name.
Qt4 application with bundle structure like that:
QtCore.framework/
QtCore -> Versions/Current/QtCore
Resources -> Versions/Current/Resources
Versions/
4/
QtCore
Resources/
Info.plist
Current -> 4
codesign --verbose --force --deep --sign "Certificate Name" Test.app
Result: Test.app: signed bundle with Mach-O thin (x86_64) [...]
"Certificate Name" is Comodo code sign certificate
codesign --verify -vvvv Test.app
Test.app: nested code is modified or invalid
codesign --verbose --verify Test.app/Contents/Frameworks/QtCore.framework
Test.app/Contents/Frameworks/QtCore.framework: valid on disk
Test.app/Contents/Frameworks/QtCore.framework: does not satisfy its designated Requirement
p.s. I have tried to sign manually all framework/dylib without option --deep and the same result.
create a folder called A inside versions with same contents of 4, change the symbolic links to the A folder especially current->A
try signing now and it may sign. But the problem may be with the binary, it will use a different framework than A, which you can check with otool -L (take care big L and not small l)
to change it, you need to use install_name_tool
good luck and have fun
I am having trouble signing Qt Based application un OS X. I am using Qt 5.3.2.
I have read various information source that contain contradictory information.
Here is the content of my application bundle after I run the bin/macdeployqt Qt utility
SimpleHello.app/
Contents/
Info.plist
PkgInfo
Frameworks/
QtCore.framework/
Resources/
Versions/
5/
QtCore
QtGui.framework/ ... same as Qt core
QtPrintSupport.framework/ ... same as Qt core
QtWidgets.framework/ ... same as Qt core
MacOS/
SimpleHello
PlugIns/ ... some plugins
Resources/
empty.lproj
qt.conf
First:
I tried: http://successfulsoftware.net/2012/08/30/how-to-sign-your-mac-os-x-app-for-gatekeeper/
However, it seems that it is not valid anymore in OS X 10.10 Yosemite
Second:
I tried: Sign a Framework for OSX 10.9
I was able to sign the whole application without any error. However, when running spctl to verify the validity of the application, I get
spctl -a -vvvv SimpleHello.app
SimpleHello.app/: rejected
source=obsolete resource envelope
origin=Developer ID Application: MY CERTIFICATE
Additionally when verifying signature with codesign, I get this:
codesign --verify --deep --verbose=4 SimpleHello.app
--prepared:/My/Path/SimpleHello.app/Contents/Frameworks/QtCore.framework
--validated:/My/Path/SimpleHello.app/Contents/Frameworks/QtCore.framework
SimpleHello.app/: embedded framework contains modified or invalid version
In subcomponent: /My/Path/SimpleHello.app/Contents/Frameworks/QtCore.framework
Third:
Added the --no-strict option in codesign verification according to: Error when export archive
It fixes the issue with codesign verification but does not fix the spctl issue.
Forth:
I tried adding the --no-legacy-signing option when signing frameworks. However I get this error when verifying the bundle signature (both with codesign and spctl
codesign --verify --deep --verbose=4 SimpleHello.app
SimpleHello.app/: code has no resources but signature indicates they must be present
Fifth:
Modified the framework structure according to:
http://qt-project.org/forums/viewthread/47768
and
https://gist.github.com/kingcheez/6154462d7734e0c0f3a4
In this case I get this error when trying to sign frameworks
SimpleHello.app/Contents/Frameworks/QtCore.framework: unsealed contents present in the root directory of an embedded framework
SimpleHello.app/Contents/Frameworks/QtGui.framework: unsealed contents present in the root directory of an embedded framework
SimpleHello.app/Contents/Frameworks/QtPrintSupport.framework: unsealed contents present in the root directory of an embedded framework
SimpleHello.app/Contents/Frameworks/QtWidgets.framework: unsealed contents present in the root directory of an embedded framework
EDIT: It seems that the issue with the unsealed contents present in the root directory of an embedded framework was because one of the simlink was malformed. It was:
QtCore.framework.framework/Versions/Current -> 5/
Instead of
QtCore.framework.framework/Versions/Current -> 5
After this fix, I still get the same result as in Sixth though.
Sixth:
Added the --no-strict option when calling codesign for Frameworks. I was able to sign all frameworks except for one
SimpleHello.app//Contents/Frameworks/QtCore.framework: signed bundle with Mach-O thin (x86_64) [.]
SimpleHello.app//Contents/Frameworks/QtGui.framework: signed bundle with Mach-O thin (x86_64) [.]
SimpleHello.app//Contents/Frameworks/QtPrintSupport.framework: code object is not signed at all
In subcomponent: /My/Path/SimpleHello.app/Contents/Frameworks/QtPrintSupport.framework/Versions/Current/QtPrintSupport
SimpleHello.app//Contents/Frameworks/QtWidgets.framework: signed bundle with Mach-O thin (x86_64) [.]
Seventh:
I posted this question since I don't know what to look for anymore
After digging a bit more, I figured out what the issue in section seventh was: Some of the Qt Framework contain bad information in the Info.plist files (framework name ends with _debug)
I came out with this script that fixes all issues (there are still a few hardcoded values that could probably get processed with some improvement to the script)
#!/bin/bash
# Script name: deploy.sh
# Following environment variables must be defined:
# - QT_FRAMEWORK_PATH
# - QT_BIN_PATH
# - CERTIFICATE
# - FRAMEWORKS
# - BAD_FRAMEWORKS
# retrieve bundle name from first parameter
BUNDLE_NAME=$1
# Run QT tool to deploy
${QT_BIN_PATH}/macdeployqt $BUNDLE_NAME
# FIX ISSUE 6
# Please note that Qt5 frameworks have incorrect layout after SDK build, so this isn't just a problem with `macdeployqt` but whole framework assembly part.
# Present
# QtCore.framework/
# Contents/
# Info.plist
# QtCore -> Versions/Current/QtCore
# Versions/
# Current -> 5
# 5/
# QtCore
# After macdeployqt
# QtCore.framework/
# Resources/
# Versions/
# 5/
# QtCore
#
# Expected
# QtCore.framework/
# QtCore -> Versions/Current/QtCore
# Resources -> Versions/Current/Resources
# Versions/
# Current -> 5
# 5/
# QtCore
# Resources/
# Info.plist
# So in order to comply with expected layout: https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html
for CURRENT_FRAMEWORK in ${FRAMEWORKS}; do
echo "Processing framework: ${CURRENT_FRAMEWORK}"
echo "Deleting existing resource folder"
rmdir ${BUNDLE_NAME}/Contents/Frameworks/${CURRENT_FRAMEWORK}.framework/Resources
echo "create resource folder"
mkdir -p ${BUNDLE_NAME}/Contents/Frameworks/${CURRENT_FRAMEWORK}.framework/Versions/5/Resources
echo "create copy resource file"
cp ${QT_FRAMEWORK_PATH}/${CURRENT_FRAMEWORK}.framework/Contents/Info.plist $BUNDLE_NAME/Contents/Frameworks/${CURRENT_FRAMEWORK}.framework/Versions/5/Resources/
echo "create symbolic links"
ln -nfs 5 ${BUNDLE_NAME}/Contents/Frameworks/${CURRENT_FRAMEWORK}.framework/Versions/Current
ln -nfs Versions/Current/${CURRENT_FRAMEWORK} ${BUNDLE_NAME}/Contents/Frameworks/${CURRENT_FRAMEWORK}.framework/${CURRENT_FRAMEWORK}
ln -nfs Versions/Current/Resources ${BUNDLE_NAME}/Contents/Frameworks/${CURRENT_FRAMEWORK}.framework/Resources
done
# FIX ISSUE 7
echo "***** Correct Frameworks Info.plist file*****"
for CURRENT_FRAMEWORK in ${BAD_FRAMEWORKS}; do
echo "Correcting bad framework Info.plist: ${CURRENT_FRAMEWORK}"
TMP=$(sed 's/_debug//g' ${BUNDLE_NAME}/Contents/Frameworks/${CURRENT_FRAMEWORK}.framework/Resources/Info.plist)
echo "$TMP" > ${BUNDLE_NAME}/Contents/Frameworks/${CURRENT_FRAMEWORK}.framework/Resources/Info.plist
done
# SIGNING FIXED FRAMEWORK
CODESIGN_OPTIONS="--verbose=4"
#echo "******* Sign QtWebEngineProcess ***********"
#codesign --force --verify ${CODESIGN_OPTIONS} --sign "$CERTIFICATE" $BUNDLE_NAME/Contents/Frameworks/QtWebEngineCore.framework/Versions/Current/Helpers/QtWebEngineProcess.app
echo "******* Sign Frameworks-subApps ***********"
codesign --force --verify ${CODESIGN_OPTIONS} --sign "$CERTIFICATE" $BUNDLE_NAME/Contents/Frameworks/*.framework/Versions/*/*/*.app
echo "******* Signing Frameworks ***********"
for CURRENT_FRAMEWORK in ${FRAMEWORKS}; do
echo "Signing framework: ${CURRENT_FRAMEWORK}"
codesign --force --verify ${CODESIGN_OPTIONS} --sign "$CERTIFICATE" $BUNDLE_NAME/Contents/Frameworks/${CURRENT_FRAMEWORK}.framework
done
# Sign plugins
echo "******* Signing Plugins ***********"
codesign --force --verify ${CODESIGN_OPTIONS} --sign "${CERTIFICATE}" ${BUNDLE_NAME}/Contents/Plugins/*/*.dylib
# Sign bundle itself
echo "******* Signing Bundle ***********"
codesign --force --verify ${CODESIGN_OPTIONS} --sign "$CERTIFICATE" $BUNDLE_NAME
# Verify
echo "******* Verify Bundle ***********"
codesign --verify --deep ${CODESIGN_OPTIONS} $BUNDLE_NAME
echo "******* Verify Bundle using dpctl ***********"
spctl -a -vvvv $BUNDLE_NAME
As for calling the script:
# Define environment variables
export QT_FRAMEWORK_PATH=/Path/To/Qt_5.3.2/5.3/clang_64/lib
export QT_BIN_PATH=/Path/To/Qt_5.3.2/5.3/clang_64/bin
export CERTIFICATE="Developer ID Application: My Certificate"
export FRAMEWORKS="QtCore QtGui QtPrintSupport QtWidgets"
export BAD_FRAMEWORKS="QtPrintSupport"
# Call itself
deploy.sh SimpleHello.app
With this script, the final output is:
SimpleHello.app/: accepted
source=Developer ID
origin=Developer ID Application: My Certificate (HASH)
I run a script similar to this after running macdeployqt:
#!/bin/bash
#copy .plist files to frameworks
cp "/usr/local/Trolltech/Qt-4.8.5/lib/QtCore.framework/Contents/Info.plist" "SimpleHello.app/Contents/Frameworks/QtCore.framework/Resources/Info.plist"
#copy folders to proper location
cp -r "SimpleHello.app/Contents/Frameworks/QtCore.framework/Resources" "SimpleHello.app/Contents/Frameworks/QtCore.framework/Versions/4/Resources"
#delete old folders
rm -rf "SimpleHello.app/Contents/Frameworks/QtCore.framework/Resources"
#create symlinks
ln -s "Versions/4/Resources" "SimpleHello.app/Contents/Frameworks/QtCore.framework/Resources"
After, I use:
codesign --deep -f -s
and it works, just add the missing frameworks in a similar fashion.
I haven't tried it with qt 5+ but it might work for it to.
So we have a certificate that allows us to sign kexts,
but when we run > sudo kextload friendly.kext, it fails
and we sign the kext we want, and to prove it's signed, here's some diagnostic output:
👉 codesign --verify -vvvv friendly.kext
friendly.kext: valid on disk
friendly.kext: satisfies its Designated Requirement
👉 spctl -a -vvvv friendly.kext
friendly.kext: accepted
source=Developer ID
origin=Developer ID Application: Friendly Corporation
/Library/Extensions
👉 codesign -dvvv friendly.kext
Executable=/Library/Extensions/friendly.kext/Contents/MacOS/friendly
Identifier=com.friendly.friendly
Format=bundle with Mach-O thin (x86_64)
CodeDirectory v=20200 size=502 flags=0x0(none) hashes=18+3 location=embedded
Hash type=sha1 size=20
CDHash=a1e2bf8d53ea67c6cfe9fc3d6d2001fe56c838a7
Signature size=8528
Authority=Developer ID Application: Friendly Corporation
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=Oct 9, 2014, 11:49:02 AM
Info.plist entries=21
TeamIdentifier=1234567890
Sealed Resources version=2 rules=12 files=1
Internal requirements count=1 size=180
👉 codesign --verify -vvvv friendly.kext
friendly.kext: valid on disk
friendly.kext: satisfies its Designated Requirement
It looks like it's signed properly;
However, when I run > sudo kextutil -v friendly.kext :
Defaulting to kernel file '/System/Library/Kernels/kernel'
Diagnostics for /Library/Extensions/friendly.kext:
Code Signing Failure: code signature is invalid
/Library/Extensions/friendly.kext appears to be loadable (not including linkage for on-disk libraries).
ERROR: invalid signature for com.techsmith.friendly, will not load
I'm thinking either I downloaded the certificate wrong (we definitely got approved for kext signing), although I tried redownloading the certificate once before so that may not be the problem.
Otherwise, it's the way that I'm signing. I'm thinking maybe it has something to do with the permissions I set on the kext before I sign them?
Has anybody seen this problem before?
Thanks in advance!
The kext signing certificate must have the extension "( 1.2.840.113635.100.6.1.18 )" listed - this is what designates it as a kext-enabled certificate. You can easily verify this by viewing it in Keychain Access.app. (it's listed near the bottom, below extension "( 1.2.840.113635.100.6.1.13 )" which I think is used for apps and thus present in all Developer ID certificates)