Clang warning about 'xar_open' API deprecation in macOS 12.0. How to address/replace with a more approprite API?

Hello!

We have code that extracts macOS Installer package (.pkg, .mpkg) signature information using APIs defined in <xar/xar.h>

The code opens the package using ‘xar_open’ API like this.

func open(file: String) throws(XarError) {
xarfile = xar_open(file, READ)
if xarfile == nil {
throw .fileOpenError
}
}

This code produces a clang warning in our CI build system when built for macOS 12 and up.

'xar_open' was deprecated in macOS 12.0: xar is a deprecated file format and should not be used.

Question #1:

  • What is the appropriate / more preferred way to extract signature information from an Installer package given that xar related APIs are deprecated?

We use xar APIs to validate the package signature prior to installation to prevent packagers not signed by our team ID from being installed.

Question #2:

  • “xar is a deprecated file format and should not be used.”. Does this phrase refer to the file format that should be avoided or the API that extract signature information?

We distribute our product using Developer ID method that using pkg/mpkg formats which I believe internally follow the same structure as xar files. I hope this message does not mean we should rethink the distribution method for our products.

Thank you.

Filed FB FB17148233 as well.

Answered by DTS Engineer in 833618022

The xar file format definitely originated with Apple. It came from an era when everything had an X in it (-:

The format was originally pitched as being a general-purposes archive format, but that never came to pass. Never bet against the venerable tar file format (-:

That explains why the <xar.h> API was deprecated. Apple recommends against using it for new applications [1]. However, the xar format is still used in a number of existing applications, most notably the flat installer package format.

IMPORTANT The installer package format is not deprecated. That deprecation notice is about the API specifically.

You have a choice of how to proceed here:

  • Suppress the deprecation warning and stay on your current path.

  • Stick with installer packages but use pkgutil to check their signature.

  • Move away from the installer package format entirely.

It’s hard to offer specific advice here. My general inclination is to move off deprecated APIs as soon as possible, but in this case the decision is tangle up with your distribution file format, and it’s hard to predict how that will pan out.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] For new applications we recommend the Apple Archive framework, which comes with its own archive format. I talk about that more in Unpacking Apple Archives.

It looks like that was a Google thing originally. After Google abandoned it, Apple didn't want to take it up.

Have you tried the standard signature verification APIs? Or various command-line looks like pkgutil, codesign, or spctl?

The xar file format definitely originated with Apple. It came from an era when everything had an X in it (-:

The format was originally pitched as being a general-purposes archive format, but that never came to pass. Never bet against the venerable tar file format (-:

That explains why the <xar.h> API was deprecated. Apple recommends against using it for new applications [1]. However, the xar format is still used in a number of existing applications, most notably the flat installer package format.

IMPORTANT The installer package format is not deprecated. That deprecation notice is about the API specifically.

You have a choice of how to proceed here:

  • Suppress the deprecation warning and stay on your current path.

  • Stick with installer packages but use pkgutil to check their signature.

  • Move away from the installer package format entirely.

It’s hard to offer specific advice here. My general inclination is to move off deprecated APIs as soon as possible, but in this case the decision is tangle up with your distribution file format, and it’s hard to predict how that will pan out.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] For new applications we recommend the Apple Archive framework, which comes with its own archive format. I talk about that more in Unpacking Apple Archives.

Written by Etresoft in 833602022
Or various command-line looks like pkgutil, codesign, or spctl?
Written by DTS Engineer in 833618022
Stick with installer packages but use pkgutil to check their signature.

Thanks for the responses!

pkgutil was considered but we wanted to avoid parsing of the command line tools output. We are primarily interested in the certificate subject names present in the package signature. The intention is to make sure that we install packages that are not only validly signed or accepted by Gatekeeper, pkgutil.

And it looks like one would need to parse the output of command line tools to check if a specific team ID is present. That's definitely doable but we wanted to look into options with proper API that we could call from ObjC/Swift before going to an option with running a command line from code.

Written by DTS Engineer in 833618022
[1] For new applications we recommend the Apple Archive framework, which comes with its own archive format. I talk about that more in Unpacking Apple Archives.

The Apple Archive option is curious. We haven't dealt with it much before. I will need to read about it to understand if it fits our use case. One of the reasons why Installer pkg format was selected is because

  • it's the same payload that is downloaded when the user starts using the product for the first time as an update that we publish in our update system which gets installed in the background using installer command.
  • Installer package contains signature information that we can validate before starting the installation.

So if Apple Archive allows us to achieve similar outcome, then it's definitely something to try out.

Accepted Answer
Written by ArthurValiev in 833625022
we wanted to avoid parsing of the command line tools output.

Right. And I generally agree that it’s better not to use a command-line tool as an API if there’s a perfectly good API available. However, this is now a judgement call as to whether <xar.h> is still a “perfectly good” API even though it’s deprecated.

Honestly, if I were in your shoes I’d probably stick with <xar.h>. You already have working code and it allows you to defer writing extra code pending any other changes that might come down the pike. The only gotcha is that you have to make sure you test on new macOS beta seeds to see if anything has broken but, given the nature of your product, you’ll want to be doing that anyway.

Oh, and you should probably file an enhancement request for a non-deprecated way to verify installer signatures. If you do, please post your bug number, just for the record.

On, and one more thing. Another way to check an installer package’s signature is with spctl:

% spctl -a -t install --raw -vvv Searchiverse.pkg
Searchiverse.pkg: rejected
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>assessment:authority</key>
<dict>
<key>assessment:authority:flags</key>
<integer>0</integer>
<key>assessment:authority:row</key>
<integer>14</integer>
<key>assessment:authority:source</key>
<string>Unnotarized Developer ID</string>
</dict>
<key>assessment:originator</key>
<string>Developer ID Installer: Quinn Quinn (SKMME9E2Y8)</string>
<key>assessment:remote</key>
<true/>
<key>assessment:verdict</key>
<false/>
</dict>
</plist>

Note that the --raw option gives you machine readable output, which is a step up from pkgutil.


Written by ArthurValiev in 833630022
So if Apple Archive allows us to achieve similar outcome

It won’t. It supports signing, so that’s your second requirement taken care of. The sticking point is your first requirement. The UI for Apple Archive is much like the UI for zip archives, which is nothing like the UI you get, and want, with an installer package.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Written by DTS Engineer in 833855022
Oh, and you should probably file an enhancement request for a non-deprecated way to verify installer signatures. If you do, please post your bug number, just for the record.

Yes. I posted a similar question in FB17148233. Added a summary of our discussion as a comment to it with an ask to provide a non-deprecated API now.

Thanks!

Written by DTS Engineer in 833855022
Note that the --raw option gives you machine readable output, which is a step up from pkgutil.

The raw output in spctl sounds interesting. Thanks for pointing it out. We will look into it.

Our current dilemma why we also considered relying on spctl is because xar API returns us subject names as strings. I haven't seen yet a way to distinguish between subjects specific to Apple vs. company specific certificates.

So when we extract information from a Developer ID Installer certificate, it gives an array like this

["<TEAMID>", "G2", "Apple Certification Authority"]

This is the result of using

xar_signature_get_x509certificate_data

API and then passing the data to

SecCertificateCopyValues

API to extract

kSecOIDX509V1SubjectName

field

We would like to make sure that the signature contains only authorized team IDs to prevent cases where unexpected team IDs are present in addition to the expected one.

The problem that sparked this discussion was the fact that the certificate that corresponds to "<TEAMID>", the actual Developer ID Installer certificate, is not trusted by a clean system. The certificates higher in the chain are trusted. Those with subject names "G2" and "Apple Certification Authority". So we cannot put a requirement for Developer ID Installer to be passing

SecTrustEvaluateWithError

check.

That is why spctl command was considered as a replacement to xar. In a way, spctl covers both bits on the validation that we are interested in. It can check that Gatekeeper accepts the package and it provides the teamID information.

I think you’ll be able to make some progress by:

  1. Repeatedly calling xar_signature_get_x509certificate_data to get the data for the entire chain.

  2. For each, call SecCertificateCreateWithData to build a certificate object for each certificate.

  3. Create a trust object with the full chain.

  4. Evaluate trust on that trust object.

There are a couple of tricky things here:

  • You need to decide what policy to pass it at step 3. In theory you should use an installer-specific policy but AFAICT that’s not public API. However, the chain does pass the basic X.509 policy (SecPolicyCreateBasicX509).

  • You should set the verify date (SecTrustSetVerifyDate) to the trusted time stamp in the signature, assuming it has one. I’m not exactly sure how to get that date.

You can make up for the lack of a policy by running extra checks yourself:

  • You can get the Team ID from the Common Name of the leaf certificate. On the Mac you can get that using SecCertificateCopyValues [1].

  • You’ll also need to check some extension OIDs. I’m not actually sure what the details are. You’ll need to work this out by checking the documents on the Apple PKI page.

Honestly though, this starting to get really ugly. If you continue down this path I’m going to double down on my recommendation that you file an enhancement request for an API that directly supports what you need.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] This is one of a raft of Security framework APIs that are available on the Mac but not any other platform. Many of them are deprecated, but not this one.

Written by DTS Engineer in 834103022
Honestly though, this starting to get really ugly.

Yeah. I agree. I definitely wouldn't want to complicate the approach even further. We have already managed to shoot ourselves in the foot with requiring trust for each certificate in the chain. So right now we have a situation where Gatekeeper successfully evaluates a package signature validity but our code treats it as invalid.

That's why I was considering to delegate the trust verdict decision to Gatekeeper and get team ID from xar APIs to use as an extra requirement without manual evaluation of trust on our side. So with that in mind, using spctl for checking signature validity and extracting specific fields from the certificate chain seems a more proper solution.

I'll look into xar options. But definitely won't continue with that if it turns out needing a private API. I would want to decrease the number of cases where we have that and not increase :)

Thanks!

Written by DTS Engineer in 834103022
file an enhancement request for an API that directly supports what you need

Filed FB17188856 specifically for providing an API to validate Installer package (.pkg) signature.

Linked the original one FB17148233 with a question about xar APIs for reference.

Clang warning about 'xar_open' API deprecation in macOS 12.0. How to address/replace with a more approprite API?
 
 
Q