<![CDATA[Jedda Wignall]]>https://jedda.me/https://jedda.me/favicon.pngJedda Wignallhttps://jedda.me/Ghost 5.82Thu, 11 Apr 2024 10:21:26 GMT60<![CDATA[Cross Platform ECIES encryption with Swift & Apple's Secure Enclave]]>https://jedda.me/cross-platform-encryption-with-apples-secure-enclave/660564abcdfe2b0001c600fcThu, 11 Apr 2024 00:51:45 GMT

A discussion of fundamentals, and some examples of cross-platform Elliptic curve-based hybrid cryptography compatible with Apple platforms and hardware-bound keys.


Apple's Secure Enclave; amongst it's many other utilities, provides excellent opportunities for data integrity and confidentiality. The ability to encipher data only decryptable by a single device and hardware-bound key is a powerful workflow; potentially even more so when this data originates from cross-platform infrastructure or applications.

For an upcoming project, I needed a consistent way to exchange encrypted data between a series of microservices and Apple devices and keys held in their Secure Enclaves. This short article will briefly touch on some hybrid cryptography fundamentals and one of Apple's implementations as part of their Security framework as well as links to some new resources I have created to help build and understand cross-platform applications.

Whilst this article and the projects and code samples it links to are inherently technical and require a base understanding of programming in Swift and Golang, the underlying concepts may be valuable to non-programmers with an interest in security on Apple platforms. In particular, I've tried to step out my commentary in the ECIES-Swift-Playground described below to be relevant to someone not familiar with the actual code and help to establish an understanding of the fundamentals.

Whilst CryptoKit provides a modern hybrid cryptography option through its implementation of the HKPE standard, this can prove a more complex build out due to the myriad of AEADs, KDFs and KEMs supported by the standard, it's nonce and sequence generation and use of authenticated encryption. Elliptic Curve Integrated Encryption Scheme (ECIES) is the primary Elliptic Curve encryption standard supported by Apple's Security framework and is a great choice for simple, secure data exchange. It shares a lot of connective tissue with HKPE, but is a little easier to implement across platforms (I plan to write a follow-up article discussing a similar implementation of cross-platform HPKE senders and receivers, and will go into more detail about this).

ECIES is a hybrid encryption scheme using Elliptic Curve keys supported by the Secure Enclave (when using a NIST P-256 curve). As a hybrid scheme, it uses asymmetric keys exchanged and trusted between a sender and receiver to derive a symmetric key that is used to actually encrypt the data. It is simple to encrypt and decrypt data on Apple platforms using this scheme, as Apple provides functions that handle most of the lift for you; namely ephemeral key generation, ECDH exchange, symmetric key derivation, nonce generation, AES-GCM sealing/opening as well as encapsulating the ciphertext along with the asymmetric key. David Schuetz provides an excellent breakdown of Apple's ECIES implementation here, and has done a huge amount of detective work to document the technical underpinnings of the process.

When data is encrypted on an Apple device under the scheme, this is effectively the process that happens behind the scenes:


Cross Platform ECIES encryption with Swift & Apple's Secure Enclave

Selection of the underlying hashing algorithm and variable IV setting used during the process is governed by a SecKeyAlgorithm; a Swift type that determines which hash the KDF function uses (SHA-224, SHA-256, SHA-384, ect.) and how the Initialisation Vector (IV) for the symmetric AES-GCM encryption is computed.

When exchanging data between Apple platforms and devices, these resultant "Combined Ciphertext Data" objects can be decrypted back to plaintext with the appropriate key simply by passing them (along with the correct algorithm selection) to SecKeyCreateDecryptedData(). The receiver retrieves and uses the ephemeral public key to perform the ECDH with their private pairing and derives the same shared key that was used to encrypt. This is great if you are working entirely within an Apple ecosystem, but if you want to exchange data cross-platform or with a backend service, good examples have been harder to find.

If you search around online for ECIES examples, you are likely to come across many that utilise the EC curve secp256k1, most known for its use as part of Bitcoin and other cryptocurrencies. Note that this curve is different from secp256r1 (which is supported by Apple implementations whereas secp256k1 is not), leading to many ECIES implementations (that hardcode the use of k1) being incompatible with Apple's. To aid in a better understanding on how to exchange cross-platform encrypted data with Apple platforms, I've created the following open source resources:

  • ECIES - a Go module that implements functions to perform ECIES encryption, decryption and key derivation compatible with Security framework. It basically does the same uplift as Apple performs for you in their Swift/Objective-C API.
  • ECIES-Go-Example - a sample Go project that utilises the ECIES module to encrypt and decrypt some example data.
  • ECIES-Swift-Playground - a macOS Swift playground that details the process of importing public and private keys from OpenSSL PEM representations, then encrypting and decrypting. It can be used alongside ECIES-Go-Example to learn how to exchange ECIES encrypted data cross-platform.

These projects and samples taken together, whilst hardly revolutionary, should contribute a fair bit towards learning and coding cross-platform ECIES data exchange. With all this in mind, encrypting data for a device's Secure Enclave is fairly simple. We can take Apple's documentation around the protection of keys with the Secure Enclave here:

Protecting keys with the Secure Enclave | Apple Developer Documentation
Create an extra layer of security for your private keys.
Cross Platform ECIES encryption with Swift & Apple's Secure Enclave

And use their examples to build out something like this:

do {
  // create our access control policy
  // so that our key is only accessible when the device is unlocked
  // and valid biometrics are presented
  var accessError: Unmanaged<CFError>?
  guard let access = SecAccessControlCreateWithFlags(
      kCFAllocatorDefault,
      kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
      [.privateKeyUsage, .biometryAny],
      &accessError) else {
          throw accessError!.takeRetainedValue() as Error
  }

  // setup our key creation attributes
  // for a 256 bit (P-256) EC key generated by the Secure Enclave
  // and with a tag we can use to query and use it later
  let attributes: NSDictionary = [
              kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
              kSecAttrKeySizeInBits: 256,
              kSecAttrTokenID: kSecAttrTokenIDSecureEnclave,
              kSecPrivateKeyAttrs: [
                  kSecAttrIsPermanent: true,
                  kSecAttrApplicationTag: "me.jedda.ECIESSecureEnclaveExample.key",
                  kSecAttrAccessControl: access
              ]
          ]

  // create our key
  var createError: Unmanaged<CFError>?
  guard let secKey = SecKeyCreateRandomKey(attributes, &createError) else {
    throw createError!.takeRetainedValue() as Error
  }

  let publicSecKey = SecKeyCopyPublicKey(secKey)
  var publicSecKeyError: Unmanaged<CFError>?
  guard let publicKeyData = SecKeyCopyExternalRepresentation(publicSecKey!, &publicSecKeyError) as? Data else {
            throw createError!.takeRetainedValue() as Error
  }

  // now we have our raw public key bytes in publicKeyData
  // which should be easily portable to wherever they need to go
  // we can encrypt data with this key, and it will only be decryptable
  // on this device with the hardware bound key in the Secure Enclave

} catch {
  print("ERROR \(error)")
}

You need to think carefully about how you use this type of encryption. Remember that with non-extractable keys; if the device dies or is lost, the data is effectively crypto-shredded. For short-lived messages and commands, this might be desirable, but just make sure that you consider these risks if you choose to encrypt anything more permanent.

If you use some of the resources I've created and linked to above, I hope you find them useful. If you have any questions or feedback, please reach out.

]]>
<![CDATA[Managed Device Attestation for Apple devices - a technical exploration]]>https://jedda.me/managed-device-attestation-a-technical-exploration/65547ceaa1f5560001ac7c66Tue, 28 Nov 2023 08:10:00 GMT

A deep dive into the current state of cryptographic device attestation on Apple platforms.


Managed Device Attestation (MDA) for Apple devices. Announced with a flurry of interest at WWDC 2022, and then..... not much activity at all. Apart from a small subset of cutting-edge users, Managed Device Attestation hasn't yet found its way to the masses - mainly hindered by slow adoption by major MDM providers and some limited use cases.

If you Google it today, you'll likely find some Apple developer documentation and a smattering of blogs from MDM & PKI vendors to explain the high-level concepts but no tangible or shipping examples of real-world use cases.

I believe we are sitting on the frontier of a transformative platform security mechanism, and hope that through reading this article, you'll agree with me that device attestation is about to become a very big deal.

This article aims to do 3 things:

  • Detail the high-level concepts of cryptographic attestation and managed Device Attestations on Apple platforms in their current state today
  • Provide a technical breakdown of the attestation process and ACME payload execution on iOS & macOS using commonly available open-source tools
  • Contribute some editorial on the current and future use case and direction of Managed Device Attestation on Apple platforms

Just a note that the information in this article has been brought together from many sources along with my own lab testing. As this is a quickly changing (and sporadically documented) topic, some of the following breakdowns may be slightly off on specifics and order of operations, however, the general concepts should be fairly sound. If there is anything here that you feel is incorrect, please reach out. I've included a list of sources in the footer.

Breaking down the core concepts

The concepts behind cryptographic device attestation aren't unique to Apple platforms. There are efforts inside Google, Microsoft and other manufacturers working to achieve the same thing - strong signed evidence of genuine, identifiable devices with hardware-bound private keys. The initial ideas around utilising WebAuthn attestations to verify manufacturer hardware identifiers stirred out of Google, with Brandon Weeks' contributions and thought leadership on this topic to be strongly admired.

The power of manufacturer-backed attestations should be easily understood. As networks and resources become more distributed and threats to data confidentiality become more aggressive, organisations are looking for more secure ways to ensure that only authorised users on authorised devices have access to sensitive resources.

Traditional efforts in this space have focused on the user & their observable properties; enforcement of strong authentication factors, session management & contextual policy on network location, to name just a few. As the perimeter shifts beyond that of traditional firewalls & the popularity of SASE & ZTNA architectures surges, the need for greater evidence of authorisation & posture of managed devices has surfaced and continues to grow. Many commercial ZTNA solutions such as Cloudflare ZTNA & Jamf Security Cloud have built-in device posture capability checking to ensure compliance with specific criteria prior to allowing access to specific applications and resources. In more traditional campus architectures, NAC solutions such as Aruba ClearPass & Cisco ISE can be integrated to consider device posture as part of their network authentication & authorisation decisions.

Device identity & posture information can come via MDM and interconnected systems, or sometimes via a client or agent running on a device. However, for many current implementations, we are making critical assumptions the information our devices and services report is trustworthy.

Why is cryptographic attestation important?

Devices can lie.

They can lie about their core identity and they can lie about specific properties - hardware configuration, OS & software versions, MAC addresses & more. Pre-Apple Silicon, Mac Admins were often using this to their advantage by overstamping known serials on VMs to test device enrollment workflows. Prior to T2, even the process of changing physical Mac hardware serials was trivial for those with the right tools.

With MDM becoming ubiquitous, we are finding ourselves more reliant on it as a source of truth, and are using management UDIDs and device identifiers to certify and link devices & posture to other security mechanisms and systems (802.1X. IdPs, ZTNA, etc). To ensure security integrity for these managed devices, we need strong evidence that a device is who it says it is, and we need this prescribed independently of the OS or user space, which if compromised could just find another way to lie about its identity or properties. By utilising each Apple device's Secure Enclave as part of the attestation process, this strong evidence is now available to us.

In most managed Apple environments, we are used to using hardware serial numbers and device UDIDs to identify and reference devices. But here's the thing; the Secure Enclave in an Apple device is an isolated secure subsystem and can't actually access the device's UDID or serial number. What it can access is its root cryptographic key UID (which is burned into each SE during manufacturing) as well as a series of register stored hashes from each stage of the most recent device boot chain. During the attestation process on Apple's servers, the former is used to match the device's permanent identifiers (serial number & UDID), and the latter are used to match versions of macOS/iOS. These are signed using Apple's attestation CA and returned back to the client.

Managed Device Attestation for Apple devices - a technical exploration

When you use MDA as strong evidence of device posture, you are choosing to place trust in the integrity & security of two primary components; the Secure Enclave and Apple's attestation of its manufacturing records. As always you should consider your individual risk profile, however, many organisations will consider this level of trust acceptable.

When asked to perform an attestation via a device management profile payload, a device reaches out over TLS to https://register.appattest.apple.com, however like most Apple services - this connection is certificate pinned, so we can't get direct visibility into the transaction. We do end up with Apple's response as part of a CBOR payload that is included with our ACME order (see below), which if we unpack (with the help of this code from Smallstep), can see how this initial attestation is represented. So what does that attestation certificate look like? Here's one from an iPad running iOS 16.5.1:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 1700180740331 (0x18bdaab48eb)
        Signature Algorithm: ecdsa-with-SHA384
        Issuer: CN = Apple Enterprise Attestation Sub CA 1, O = Apple Inc., C = US
        Validity
            Not Before: Nov 16 00:25:40 2023 GMT
            Not After : Nov 16 00:25:40 2024 GMT
        Subject: CN = 84d19f4396ae30c72ec7e4c78ae20fd14cc4bfc5f079ee0b992e928c6fc0ce43, OU = AAA Certification, O = Apple Inc., ST = California
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (384 bit)
                pub:
                    04:bd:ed:3d:85:8e:65:bd:8a:5d:c0:99:19:22:65:
                    5e:31:08:0e:26:73:3b:7e:f6:b9:c0:c9:c5:d8:54:
                    b7:c0:79:fe:c2:34:29:33:b1:0c:31:a7:b7:f2:5d:
                    0a:6d:91:e2:b4:bc:e4:34:f9:f5:dc:e9:79:c7:39:
                    c7:13:b4:6d:16:73:b8:26:0a:3d:c2:09:fd:2f:7e:
                    1f:2c:3c:c2:1f:20:ef:d4:9c:36:0b:ea:8f:e0:78:
                    fe:27:5e:de:4f:fd:46
                ASN1 OID: secp384r1
                NIST CURVE: P-384
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Key Usage: critical
                Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
            1.2.840.113635.100.8.10.2: 
                16.5.1
            1.2.840.113635.100.8.9.1: 
                DMH9ZK607VP8
            1.2.840.113635.100.8.9.2:
                4a6ec46c7aaf514cc1abf85c37a87fd0fda903e4
            1.2.840.113635.100.8.11.1: 
                =.=.dx...............B..).5..8].
    Signature Algorithm: ecdsa-with-SHA384
    Signature Value:
        30:64:02:30:60:1b:eb:16:24:9e:30:5b:a2:d9:92:7a:ee:9a:
        98:4e:da:1c:8f:40:7a:4a:69:8b:b3:fa:8d:16:1c:5b:cf:71:
        17:3d:89:b3:e7:b8:8f:0a:c5:28:f9:38:ff:4c:8e:bb:02:30:
        10:1a:2b:6f:fa:94:c7:6f:73:d2:7f:c9:ea:36:d0:ee:28:02:
        c1:36:c3:7d:3c:49:7e:7a:57:7e:c3:a3:40:16:99:c1:39:28:
        88:9d:73:b4:98:8b:cb:32:3b:47:19:1a

I've highlighted some interesting parts of the certificate info in yellow, namely:

  • An issuer of Apple Enterprise Attestation Sub CA 1. This is an intermediate CA signed by the Apple Enterprise Attestation Root CA. Interestingly the root is not available via any form of authorityInfoAccess, but is available for download from Apple's private PKI repository. All Apple attestations must chain back to this root CA during challenges in order to be validated. This validation is the responsibility of the ACME server processing the device-attest-01 challenge.
  • A public key starting 04:bd:ed:3d:85:8e:65:bd. This is the public pairing to our hardware-bound private key generated and stored in the Secure Enclave.
  • 16.5.1 - the device's current iOS version. This has been matched using the device's boot chain hashes and is available as an attested property.
  • DMH9ZK607VP8 - the device serial number. One of the permanent identifiers that can be used to complete the device-attest-01 challenge.
  • 4a6ec46c7aaf514cc1abf85c37a87fd0fda903e4 - the device UDID. Another permanent identifier that can be used to complete the device-attest-01 challenge. This is an interesting identifier that can differ in use case based on platform. I'll speak more to this later in the Behaviours on macOS vs iOS section of this article.

Now the device has its Apple attestation, but that's nowhere near the end of the story. Those familiar with X.509 might note that the attestation certificate doesn't have any EKUs - it's not usable nor designed to be used for anything beyond attestation, and it's not linked to or issued from your PKI. For that, we need ACME.

ACME & the device-attest-01 challenge

Those not familiar with the ACME protocol will likely have heard of Let's Encrypt - an extremely popular free online certificate authority that uses ACME for certificate issuance. ACME is a client & server protocol that uses "challenges" to ensure a client can prove control of specific identifiers for a certificate to be issued. Traditional ACME challenges include http-01; a challenge where a client must place a token file on a publicly available web server to prove control of the filesystem, and dns-01; a challenge that asks for a specific value in a DNS TXT record for a domain to prove control of the DNS zone.

These challenges, alongside open source automatable clients such as Certbot have led to Let's Encrypt issuing approximately 7% of all public TLS certificates on the internet using the ACME protocol. These challenges are however focused (for the most part) on the issuance of server certificates (for a website, proxy or other TLS service) and not for client identification or authentication.

Enter device-attest-01 – a draft extension by Brandon Weeks that specifies new mechanisms utilising WebAuthn to allow a device to complete a challenge as to its permanent identity. It sets out many of the concepts I discuss in this article and is a good read if you want to understand more at a technical level. As a draft, this extension is still open for development and change, however, it has been accepted by IETF as a WG Document (working group document) which means it is being actively developed with the goal of becoming a part of the standard.

For their implementation of Managed Device Attestation, Apple has utilised ACME and device-attest-01 as part of it's com.apple.security.acme device management payload. This allows devices to request attestation from Apple, then forward the signed attestation & CSR to a supported ACME server in exchange for a signed certificate from organisational PKI.

For the following breakdown, we are going to be looking at JSON requests from Apple's com.apple.security.acmeclient as well as logs from step-ca, an excellent open-source Certificate Authority with built-in support for ACME & the device-attest-01 challenge. Smallstep; the developers of step-ca have done a massive amount of work to build support & foster interest in device attestation and they should be commended for their efforts.

I think the following breakdown does a pretty good job of outlining how the ACME client-server transaction works, but note that for brevity a lot of identifiers, JSON wrapping, and some beige steps have been removed. If you want to see all this for yourself in full colour, watching the step-ca logs whilst also snooping an ACME transaction through something like Proxyman will expose all the data you need.

Where you see "Credibly" or "pki.credibly.cc" referenced below - that is my example organisation and domain used for testing these flows.

Here's what an ACME transaction looks like for an Apple device:

The client performs a GET on the ACME directory URL (embedded in the device management payload) to discover specific endpoint URIs for ACME account creation & certificate ordering:

method=GET path=/acme/mda/directory response="{"newNonce":"https://pki.credibly.cc/acme/mda/new-nonce","newAccount":"https://pki.credibly.cc/acme/mda/new-account","newOrder":"https://pki.credibly.cc/acme/mda/new-order","revokeCert":"https://pki.credibly.cc/acme/mda/revoke-cert","keyChange":"https://pki.credibly.cc/acme/mda/key-change"}" size=677 status=200 user-agent=com.apple.security.acmeclient/1.0

Note that whilst endpoints are available for certificate revocation and key management, to my knowledge Apple's ACME client doesn't currently use them.

The client performs a HEAD on the "newNonce" endpoint to get a nonce value that is used as a one-time anti-replay nonce on subsequent operations:

method=HEAD path=/acme/mda/new-nonce size=0 status=200 user-agent=com.apple.security.acmeclient/1.0

You can read more about how this nonce is used in the ACME spec.

The client performs a POST to register a new account on the ACME server:

method=POST path=/acme/provisioner/new-account response="{"status":"valid","orders":"https://pki.credibly.cc/acme/mda/account/.../orders"}" size=188 status=201 user-agent=com.apple.security.acmeclient/1.0

During this, it agrees to your ACME server's TOS on your behalf!

The client now places an order for a certificate using the ClientIdentifier property set in the payload. In step-ca's current implementation, this must match one of the permanent identifiers the device has achieved attestation for:

{"identifiers":[{"type":"permanent-identifier","value":"DMH9ZK607VP8"}]}

The requirement for the ClientIdentifier to match a permanent identifier is not a part of the specification and this may change in the future.

The server confirms the order and returns an "authorizations" endpoint for the client to check for challenges:

path=/acme/mda/new-order response="{"id":"...","status":"pending","expires":"2023-11-17T08:13:01Z","identifiers":[{"type":"permanent-identifier","value":"DMH9ZK607VP8"}],"notBefore":"2023-11-16T08:12:01Z","notAfter":"2023-11-17T08:13:01Z","authorizations":["https://pki.credibly.cc/acme/mda/authz/..."],"finalize":"https://pki.credibly.cc/acme/mda/order/.../finalize"}" size=575 status=201 user-agent=com.apple.security.acmeclient/1.0


The client checks for appropriate challenges and finds a device-attest-01 which it attempts to solve by forwarding the WebAuthn attestation statement it acquired earlier. The server validates this against Apple's attestation root CA, and if valid, accepts the challenge and lets the client know that it was successful:

method=POST path=/acme/mda/authz/... response="{"type": "device-attest-01", "status": "valid","validated": "2023-11-17T00:25:40Z"}" size=366 status=200 user-agent=com.apple.security.acmeclient/1.0


After finalising by providing a CSR with a public key matching that of the attestation leaf, the client finally receives a signed certificate from the server:

method=POST path=/acme/attest_nohook/certificate/CEE... certificate="MII..." issuer="Credibly Intermediate Devices CA"  public-key="ECDSA P-384" size=2067 status=200 subject=DMH9ZK607VP8 user-agent=com.apple.security.acmeclient/1.0 valid-from="2023-11-21T03:57:47Z" valid-to="2023-11-22T03:58:47Z"


Here's what the issued certificate looks like (using a default step-ca template):

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            3d:fb:bd:f5:75:47:c2:a4:d8:96:72:44:a8:3e:c1:73
        Signature Algorithm: ecdsa-with-SHA384
        Issuer: C = AU, O = Credibly, CN = Credibly Intermediate Devices CA
        Validity
            Not Before: Nov 21 03:57:47 2023 GMT
            Not After : Nov 22 03:58:47 2023 GMT
        Subject: CN = DMH9ZK607VP8
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (384 bit)
                pub:
                    04:bd:ed:3d:85:8e:65:bd:8a:5d:c0:99:19:22:65:
                    5e:31:08:0e:26:73:3b:7e:f6:b9:c0:c9:c5:d8:54:
                    b7:c0:79:fe:c2:34:29:33:b1:0c:31:a7:b7:f2:5d:
                    0a:6d:91:e2:b4:bc:e4:34:f9:f5:dc:e9:79:c7:39:
                    c7:13:b4:6d:16:73:b8:26:0a:3d:c2:09:fd:2f:7e:
                    1f:2c:3c:c2:1f:20:ef:d4:9c:36:0b:ea:8f:e0:78:
                    fe:27:5e:de:4f:fd:46
                ASN1 OID: secp384r1
                NIST CURVE: P-384
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
            X509v3 Subject Key Identifier: 
                B1:A3:9A:6A:E2:7A:17:19:BA:9C:B0:44:3D:6E:7A:7A:57:60:34:FD
            X509v3 Authority Key Identifier: 
                8B:2A:03:BC:F7:9B:F9:77:F8:FF:AB:ED:32:4C:71:5E:F9:61:DA:14
            1.3.6.1.4.1.37476.9000.64.1: 
                mda

Let's note a few things about this certificate (again highlighted in yellow):

  • An issuer of Credibly Intermediate Devices CA. This is our intermediate Certificate Authority for which we own and issue the PKI.
  • A certificate common name (CN) with the serial number of the device; DMH9ZK607VP8. Currently, in step-ca it is a requirement that the CN match one of the attested permanent identifiers.
  • A public key starting 04:bd:ed:3d:85:8e:65:bd - note this is the same public key that was originally attested by Apple. With this, we know that Apple has attested this pair's private key to be hardware bound in the device's Secure Enclave.
  • An OID (1.3.6.1.4.1.37476.9000.64.1) with a value mda. This is the name of the provisioner within step-ca used to issue our certificate.

You might also note that this certificate now has an EKU for "TLS Web Client Authentication", which means it can be used for 802.x, VPN & Mutual TLS, etc. Its properties are actually fully customisable and are governed by step-ca X.509 templates. In a section below, I'll detail a method of enriching this certificate with additional data about the device and assigned users.

OK - we did it. We have a beautiful ECC private key stored in and protected by our Secure Enclave and a matching certificate signed by our organisational PKI. Surely this is the end of the story, right?

No - as you'll read; there are some specifics on how we can use these resultant certificates on Apple platforms that are very important to understand.

Behaviours on macOS vs iOS

MDA on iOS devices came first in 2022 and with iOS 16, whilst the Mac gained support in 2023 with macOS 14.0 Sonoma (although you might not know it beyond some WWDC content and this reference here).

Whilst the same MDM profiles can deploy ACME certificates to both iOS & macOS systems, there are some significant differences in the behaviour and usability of these certificate identities across each platform.

These differences provide challenges in consistent use cases for MDA ACME certificates, and it's a little unclear if some of these differences are deliberate design decisions, or were born out of intricacies in variances between Apple's OSes.

Keychains

Admins familiar with macOS may only be used to only a couple of file-based keychain types, traditionally a login keychain for each user of a Mac and a System keychain that stores both root certificates and global certificates and credentials (such as Wi-Fi passwords).

There is another class of keychain that is more opaque to user space called the Data Protection keychain. This is a complex topic that dances outside of the scope of this article, but suffice it to say that items in the Data Protection keychain may not be available to all apps (and sometimes not at all in user space with public APIs).

With the Data Protection Keychain, we also come across Keychain Access Groups. A feature born in iOS and later brought back to macOS, this allows for sandboxing and sharing of keychain items with a group of applications sharing a team or code signing entitlement. Purists out there will know this description & illustration is a bit of a simplification, but forgive me whilst illustrating a point:

Managed Device Attestation for Apple devices - a technical exploration

On iOS, Apple uses a shared Keychain Access Group across a slew of it's apps and OS services. This includes Safari, Mail, and crucially MDM-issued ACME certificates. Apps in other keychain groups (or no group at all) have no access or visibility into Apple's keychain items, and thus can't make use of MDM provisioned certificate identities.

This is obviously a great implementation of credential sandboxing that severely limits third-party ability to access secrets for a developer's apps however, because there is no centralised control within MDM (or elsewhere) to allow or whitelist identities to other apps or groups, provisioned identities are only available within the MDM profile itself (802.1X or VPN), or to Apple applications (Safari & Mail). On iOS, this allows for some powerful Mutual TLS (mTLS) flows using MDA ACME certificates within Safari however, the lack of a Certificate Preference payload on iOS means the ease and enforcement of mTLS browser flows is limited. Additionally, apps such as Chrome, Edge, Brave, or managed browser contexts or application-embedded WebViews have no access to MDM-provisioned certificate identities, which further limits mTLS usage.

macOS is currently even more of a more conservative story. Presumably due to differences in keychain implementations compared to iOS (or as a deliberate design decision), a fully issued MDA certificate is almost opaque to the OS itself and doesn't appear in Keychain Access or even via the security command. MDM can get the full certificate via the CertificateList command, and a client can get limited information via the /usr/libexec/mdmclient QueryCertificates command, but for the most part, can't easily access the public or private keys. Additionally, because the certificate exists outside the appropriate keychain access groups (or isn't available at all through public APIs), the identity isn't available within Safari for mTLS use, nor to any third-party applications.

I've been doing a fair bit of work lately on ZNTA platform implementation with Apple endpoints. In doing so, we are looking at user and device posture as part of an ABAC model for resource authorisation, and in some cases, the gauntlet we are asking a subject to run & conquer is significant (device compliance baselines, running service binaries, code signing validation, etc.). If a client such as Cloudflare's could access and validate an MDA certificate from your corporate PKI as part of a device posture assessment, wouldn't you say that (paired with other challenges) that would represent very strong evidence of an authorised device in an understood state?

Additionally, mTLS is a great use case for MDA-verified certificates which works today on iOS but not on macOS. Built-in support for mTLS in cloud platforms such as Amazon Web Services, Azure, Cloudflare ZTNA & many more often makes it simple to require mutual authentication and encryption for internet services without traditional VPNs. In an increasingly mobile world, mutual TLS makes natural sense as a strong security control - either for standalone services & APIs or as part of a more mature zero-trust strategy. Cloudflare has a great rundown on Mutual TLS which is worth a read if you aren't familiar with its use.

This is pure conjecture, but perhaps we could see a future implementation across all Apple platforms similar to the whitelisting of System Extensions for hardware-bound, attested ACME identities - one where specific team or bundle identifiers are whitelisted to allow them access through the SecItem API. I think device identity is going to become a big enough deal that a mechanism like this (or something else like a developer entitlement) makes natural sense.

Device UDIDs

Another difference in behaviour that I have observed relates to device UDIDs and how they are reported and used on iOS vs macOS (and then Apple Silicon vs Intel with T2). This is undoubtedly expected behaviour, however i'm yet to find any definitive information or documentation, and as you'll see; these make usage of UDIDs more difficult on macOS when paired with external tools.

On iOS, the UDID returned as part of a device attestation is the standard device UDID reported to MDM. It can be easily searched and matched using most MDM APIs and is a ubiquitous identifier that is consistent across many platforms and apps referencing iOS devices and their posture.

On macOS, this is a different story. On Apple Silicon Macs, the permanent identifier returned via a device attestation is the Provisioning UDID viewable in a Hardware Overview in System Report. On attestations for Intel Macs with a T2 chip, the returned permanent identifier is a different 24-character UDID in the same format as the Provisioning UDID - however it doesn't match up or show in any system profile or hardware dumps that I can locate. Additionally, on these systems, System Report shows the Provisioning UDID and Hardware UUID as identical.

Here's an example of what this looks like on an Apple Silicon MacBook Pro vs an Intel MacBook Air:

Managed Device Attestation for Apple devices - a technical exploration

Documentation is sparse around the Provisioning UDID on the Mac platform, so I'm inferring a lot from my lab testing. I'm familiar with its use within developer ecosystems but can't find good references on its use in platform security. If anyone has anything further to offer on this, please reach out as I'd love to better understand this and update this article with something more definitive.

In any case, these differences make the UDID hard to rely on for Macs when trying to match an identifier in any MDM or separate system. In the next section, I'll look a little more at why you may want to do any matching at all.

Gatekeeping device-attest-01 in production

device-attest-01 is an interesting challenge. Paired with manufacturer attestation (and the ACME server's validation of an attestation chain) it can provide powerful evidence of a device's genuine identity, but neither Apple nor your PKI has any direct visibility as to that devices connection to your organisation or to any particular user.

An appendix item in the device-attest-01 draft details a concept called External Account Binding as a control to gatekeep authorised devices during the ACME account creation and order process, however at the current time, this is not supported by Apple's ACME client.

Consider this in production. Perhaps your users are already utilising a mature ZNTA, SASE or cloud architecture and you consider it trivial for you to protect access to a HTTPs endpoint - awesome! For most deployments, users will be distributed and enrollment into PKI may be a postured prerequisite to the aforementioned secure connectivity pathways (if they exist at all), so it's natural to assume that many ACME CAs and provisioners will end up internet accessible. The issue with this is that presently; as long as an Apple device can attest itself as any piece of genuine Apple hardware, it can enroll in your enterprise PKI - this is obviously not workable for most organisations.

Controls need to be put in place to ensure that only authorised devices can access signed ACME certificates using your PKI. In the future, better MDM integration with ACME (particularly for actual MDM enrollment), may facilitate these controls naturally, however additional ACME payloads may still be required for other services (802.X, VPN, etc), just as exists today with SCEP and MDM such as Jamf.

For now, Smallstep suggests some security through obscurity by randomising ACME provisioner names and blocking the enumeration of provisioners when step-ca is internet-facing. In addition, they outline and recommend the use of webhooks to provide decisioning and enrichment of all of their certificate types. I respect their position here, as they are limited by the constraints of both device-attest-01 and Apple's ACME client implementation, but there has to be a better way. It's worth noting that Smallstep's commercial products are excellent and have these authorisation controls built in.

I've attempted to fill a hole here with a new open-source middleware for step-ca called step-posture-connector. It's a middleware tool that utilises the webhook functionality in step-ca to provide device identifier authorisation as well as the ability to enrich resultant X.509 certificates with user data. Today it supports flat files (JSON & CSV) and Jamf as a provider of device, group & user information, but if it proves helpful, its vision would be to expand to additional MDM providers (Intune, Kandji, Mosyle, etc.) as well as potentially other sources of asset management and ITSM platforms.

If you are considering rolling production ACME flows, or even just testing using step-ca, it's worth a look, and I'd love to hear feedback or see contributions from the community if you feel there is value here.

Mutability of attested properties

When attesting devices, Apple includes some properties that are considered immutable (hardware serial number & UDID) and some that are mutable, such as OS versions that are subject to change as a device updates.

To this point, this article has focused on device attestation via ACME Device Management payloads, however another option for device attestation exists to MDM through it performing a direct DeviceInformation query command. The idea here is that an MDM can ask for a refreshed attestation statement from Apple on a device's identity & properties, effectively getting a signed statement of a device's component versions & other properties independent of its own checks (via binary or scripting or whatever other method it normally uses). I think this will be broadly used in the future to allow MDM to verify and validate important device security parameters. The only current caveat on this is that Apple's servers currently limit fresh device attestations to one every 7 days, so usage cadence must be considered and not used for quick, punchy workflows where you need to see attested change of these mutable properties.

Managed Device Attestation for Apple devices - a technical exploration

Announcements at WWDC 2023 discussed some additional properties coming to attestations on the Mac, including SIP & Secure Boot status, Kernel Extension allowance, and specific Secure Enclave enrollment IDs, so the assumption is that as time goes on, Apple will continue to add select properties to attestations in DeviceInformation queries; most of which will likely be some form of mutable value (versions, status booleans, or other descriptors). It's a good flexible mechanism that allows Apple to provide access to new feature sets over time using a very consistent approach that can be supported by MDM providers without much additional effort.

It will be interesting to see how MDM providers and other security tech use and expose these properties, and it's definitely worth knowing about them as you consider how you might take advantage of attestation on Apple platforms.

Sending your own ACME payloads via MDM

At the present time, there is limited support for the required payload (com.apple.security.acme) within the GUI of major MDM platforms (although it's there in Mosyle).

If you wish to test ACME payloads, you may need to author your own .mobileconfig plist and upload it into your MDM. I've included an example below that can be tailored to your needs:

You'll need to modify the ClientIdentifier value if you wish to target a UDID as the device's permanent identifier - however make sure to note the platform differences outlined above. You'll be able to see issues with the attestation (such as non-matching permanent identifiers) in the step-ca logs, so that's a great place to start if you want to experiment.

Permanent identifiers & MDM enrollment types

As a privacy-focused company, it wouldn't be a new Apple feature without some caveats around device anonymisation. For MDA this comes in the form of differences when a device is User Enrolled into MDM; namely the serial number and UDID being completely omitted in attestations when User Enrolment is used for a device.

This is obviously a design decision, and for the types of organisations likely wanting to implement the initial voicings of Apple device attestation; probably not a big deal. It's worth remembering that one of the features of Account Driven User Enrollment is ongoing authentication, & that paired with a cryptographically attested device could be a very effective security control in BYOD environments. During my research I've seen references to some other anonymised identifiers for devices and the secure enclave, so hopefully we will see some future updates in this space that provide better support for all enrollment types.

Ephemeral identities & the STAR dream on Apple platforms

If you'll allow, I'll close this out with a little bit of editorial on where I believe cryptographic device attestation on Apple platforms could lead us.

The concept of STAR (Short Term Automatically Renewed) speaks to a world beyond traditional revocation methods; where short-living ephemeral certificates are issued by PKI and require renewal or re-issue at extremely short intervals. By pairing short-lived certificates with the principle of least privilege, we are massively limiting our exposure factor for compromised credentials. We see this in the DevOps world where ephemeral containers and serverless architectures use short-lived certificates and mTLS connectivity in completely automated settings. If a key and it's certificate only live for minutes or hours, do we need to worry about CRLs or OSCP in most environments?

At the present time, Apple's com.apple.security.acmeclient doesn't support certificate renewal and treats each order as a brand new one - including the generation of a new private key. Given that there are no real current content encryption use cases for ACME payloads (S/MIME, etc.), and the key is hardware-bound anyway, this probably doesn't really matter. For mTLS & 802.1X and VPN payloads, we aren't generally validating or pinning to specific public keys - just issuance from a trusted CA.

We haven't yet seen widespread adoption and push of MDA from the most popular MDM providers. I suspect this is rooted in the following (amongst other things):

  • SCEP's position as the technical core of many MDM enrollments today
  • Some of the platform inconsistencies discussed in this article
  • A little bit of arrested development stemming from Declarative Device Management and natural changes to how MDM will interact with devices in the future

When we do see better upfront adoption, hopefully we see some of the niceties baked in (such as automated renewals, ect) that we are used to with SCEP profiles. I think it's natural that ACME will replace SCEP on Apple platforms over the next few years, but how quickly this happens remains to be seen.

Imagine a future where Declarative Device Management is leveraged to allow the automatic issuance and renewal of an ephemeral attested device identity at short intervals on Apple platforms (and the keychain access issue is solved, and MDM profile replacement/failure/rollback is consistent across platforms) - 🤩. Paired with modern zero-trust concepts, this would be an extremely effective technical security control.

I really hope that you've found this deep dive into a lesser-understood concept interesting, and I would love to hear from you if you have questions, comments, or disagreements.

I truly believe that the future is extremely bright for secure device identity on Apple platforms. I think manufacturer attestation is going to become a massive part of the enterprise security story, and I can't wait to see where the path leads.


Sources

The following is a list of sources that I've referenced and might be of interest to you if you'd like to continue learning about this topic:

]]>