API for App Transport Security

I know that ATS needs to be configured statically at build time and is not meant to be (re-)configured at runtime (to quote Quinn: "[...] if ATS is enabled for a domain, developer code should not be able to decrease security for that domain.", cf. https://forums.developer.apple.com/message/159271#159271), but what if I want to increase security? From the documentation: "You can also increase a named domain’s protections by requiring Certificate Transparency" (cf. https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35).

We have an app that supports connecting to more or less arbitrary hosts and would like to be able to utilize CT for any host that supports it, which obviously we don't know at build time.

To the best of my knowledge there is no way to achieve that; am I correct?

Accepted Reply

I wanted to post a summary of what I learnt about this:

  • NSRequiresCertificateTransparency
    is an override for the platform default. If you set it to true, the connection will require certificate transparency (CT) on all versions of the OS which support
    NSRequiresCertificateTransparency
    . If you set it to false, or leave it out entirely, the platform default will apply.
  • Apple’s CT policy is covered by the Apple's Certificate Transparency policy article published by Apple Support.

    This document is somewhat vague about when that policy applies. I have confirmed that it is enforced by iOS 12.1.1 (and the related watchOS and tvOS releases) and macOS 10.14.2.

  • This policy applies to TLS connections made using Apple’s TLS implementation, regardless of the source of the connection. That is, it applies to built-in apps (like Safari), other system processes, and third-party apps equally.

  • This policy may or may not apply to apps that use their own TLS stacks:

    • If the app uses its own TLS stack but uses

      SecTrust
      to do the trust evaluation, the policy applies as above [1].
    • If the app does its own trust evaluation, it’s up to the app to implement CT.

  • This policy does not apply to certificates issued via custom CAs, where the root certificate is install via MDM, a configuration profile, and so on.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
(r. 49103522)

[1] The one caveat here relates to how the TLS implementation passes signed certificate timestamps (SCTs) to the trust object. Remember that there’s three ways to get SCTs:

  • Embedded in the certificate. This Just Works™

  • OCSP. The TLS implementation must get the OCSP response and apply it to the trust object via

    SecTrustSetOCSPResponse
    .
  • TLS

    signed_certificate_timestamp
    extension. Currently there is no way to pass the contents of that extension to a trust object, although we expect to provide such a mechanism in the future (r. 45545270).

Replies

I apologise for being a bit wishy-washy here; I have limited direct experience with certificate transparency (CT). If you want definitive answers, open a DTS tech support incident so that I can allocate time to research this properly.

I believe that modern versions of iOS will do a CT evaluation for every TLS connection, and will fail the connection if CT indicates a problem. You don’t need to set

NSRequiresCertificateTransparency
to get that. Rather,
NSRequiresCertificateTransparency
tells the system to require CT, that is, fail your request if CT can’t be done at all.

Also, you may be able to get more info about the CT state by overriding HTTPS server trust evaluation and looking at the

kSecTrustCertificateTransparency
property of the trust result.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks Quinn, I may file a DTS incident to have this addressed in greater depth.

However, I have one more - somewhat related - question: As far as I can tell there is no way to require CT for _all_ network connections since the corresponding Info.plist key can only be added inside an exception dictionary - or is it possible to specify an ATS exception providing a wildcard for the <domain-name-string>, e.g. '*' (apparently it is not possible to add NSRequiresCertrificateTransparency as a primary key)?

Regards,

Jochen

As far as I can tell there is no way to require CT for all network connections …

Correct. The approach you mooted won’t work because exceptions (the keys to

NSExceptionDomains
) always apply to a concrete domain.

btw Modern versions of iOS require CT by default. See this Apple Support article for more. The interaction between this policy change and ATS is one of those parts of the CT story that I’m still a little hazy on )-:

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi Quinn, I assume you are referring to this sentence of said support article:

"Publicly trusted Transport Layer Security (TLS) server authentication certificates issued after October 15, 2018 must meet Apple's Certificate Transparency (CT) policy to be evaluated as trusted on Apple platforms."

Does that mean that we don't have to require CT at all anymore?

FWIW, I opened a TSI (#709328399) to investigate this.

I wanted to post a summary of what I learnt about this:

  • NSRequiresCertificateTransparency
    is an override for the platform default. If you set it to true, the connection will require certificate transparency (CT) on all versions of the OS which support
    NSRequiresCertificateTransparency
    . If you set it to false, or leave it out entirely, the platform default will apply.
  • Apple’s CT policy is covered by the Apple's Certificate Transparency policy article published by Apple Support.

    This document is somewhat vague about when that policy applies. I have confirmed that it is enforced by iOS 12.1.1 (and the related watchOS and tvOS releases) and macOS 10.14.2.

  • This policy applies to TLS connections made using Apple’s TLS implementation, regardless of the source of the connection. That is, it applies to built-in apps (like Safari), other system processes, and third-party apps equally.

  • This policy may or may not apply to apps that use their own TLS stacks:

    • If the app uses its own TLS stack but uses

      SecTrust
      to do the trust evaluation, the policy applies as above [1].
    • If the app does its own trust evaluation, it’s up to the app to implement CT.

  • This policy does not apply to certificates issued via custom CAs, where the root certificate is install via MDM, a configuration profile, and so on.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
(r. 49103522)

[1] The one caveat here relates to how the TLS implementation passes signed certificate timestamps (SCTs) to the trust object. Remember that there’s three ways to get SCTs:

  • Embedded in the certificate. This Just Works™

  • OCSP. The TLS implementation must get the OCSP response and apply it to the trust object via

    SecTrustSetOCSPResponse
    .
  • TLS

    signed_certificate_timestamp
    extension. Currently there is no way to pass the contents of that extension to a trust object, although we expect to provide such a mechanism in the future (r. 45545270).

I have a few updates for the above.

Earlier I wrote:

Currently there is no way to pass the contents of that extension to a trust object, although we expect to provide such a mechanism in the future

Dude, the future is now! iOS 12.2 added

SecTrustSetSignedCertificateTimestamps
. Yay!

Also, I wrote:

This policy applies to TLS connections made using Apple’s TLS implementation, regardless of the source of the connection.

One thing I should have noted is that this can be configured via the Certificate Transparency payload (

com.apple.security.certificatetransparency
) in a configuration profile. See Configuration Profile Reference for details.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for the updates, Quinn!

Apple defines kSecTrustCertificateTransparency is available from starting iOS 9.


SecTrustCopyResult value return kSecTrustCertificateTransparency value only later iOS 12.1.

For iOS 9 , 10 and 11 kSecTrustCertificateTransparency is missing even for secure server which has Certificate Transparency Log.


Tried by Enabling NSRequireCertificateTransparency Key on Plist as well.

Very Hard to find out related resource and implementation.