Extract Installer Package Signing Certificates from xip archive
It's possible to extract Code Signing Certificates (CSCs) from an .app or signed .dmg as ASN.1 (DER) with
codesign -d --extract-certificates prefix /path/to/file.dmg
After that you can do stuff with it using openssl
, security
etc.
My goal is to do the same for signed xip archives, which use Installer Package Signing Certificates (IPSCs). You can verify xip signatures with
pkgbuild --check-signature /path/to/archive.xip
But there doesn't seem to be an option to actually export the certificates the way codesign can do it with CSCs.
Is there a way to do it from the command line?
The eventual goal is to deal with xip archives that are signed with self-signed/self-issued IPSCs. It will be a script that first checks the signature with pkgbuild
, and then, if the user wants to, it should export the certificates, and then add them to the keychain as trusted. I know you could always just dequarantine the xip file with the self-signed certificate, and this will be an additional option, but this is always on a per-file basis, so there also has to be the ability to extract the certificates (root/leaf) and import them into keychain as trusted (or trusted root). How I'll do the latter I don't know yet, but first thing's first.
Thank you for your help. (This is my first post at AskDifferent.)
Solution 1:
I think it works with the following command:
xar --dump-toc="${HOME}/Desktop/header.xml" -f /path/to/your/archive.xip
This will write an xml file called "header" onto your desktop, and that one contains the X509 certificates. You only need to parse it; maybe jq
will do the job best.
Edit: however, jq
isn't native macOS, so it has to be with xmllint etc. This below works. It will put all certificates in your home folder.
FILEPATH="/path/to/your/archive.xip"
FILENAME=$(/usr/bin/basename "$FILEPATH")
/usr/bin/xar --dump-toc=- -f "$FILEPATH" \
| /usr/bin/xmllint --xpath '//signature[@style="RSA"]' - \
| /usr/bin/sed -n '/<X509Certificate>/,/<\/X509Certificate>/p' \
| xargs \
| /usr/bin/awk '{ \
gsub("<X509Certificate>","-----BEGINCERTIFICATE-----"); \
gsub("</X509Certificate>","-----ENDCERTIFICATE-----"); \
print}' \
| /usr/bin/awk '{gsub(" ","\n"); print}' \
| /usr/bin/awk '{ \
gsub("BEGINCERTIFICATE-----","BEGIN CERTIFICATE-----\n"); \
gsub("-----ENDCERTIFICATE","\n-----END CERTIFICATE"); \
print}' \
| /usr/bin/csplit -k -s -n 1 -f "$FILENAME"-cert - '/END CERTIFICATE/+1' '{3}' 2>/dev/null
for CERT in *"-cert"* ; do
if [[ $(/bin/cat "$CERT") == "" ]] ; then
rm -rf "$CERT"
else
mv "$CERT" "$CERT.pem"
fi
done