Skip to content

Instantly share code, notes, and snippets.

@Sherlouk
Last active December 10, 2023 19:24
Show Gist options
  • Star 55 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Sherlouk/ba24f6366cd2cb1f9ad9c400ca18ad09 to your computer and use it in GitHub Desktop.
Save Sherlouk/ba24f6366cd2cb1f9ad9c400ca18ad09 to your computer and use it in GitHub Desktop.
Debug Profiles - Securely debugging in production

Blog post: https://blog.sidetrack.app/debugging-in-production

Creating the Certificates

  1. Open Keychain Access

  2. Click Keychain Access, Certificate Assistant, and Create a Certificate Authority

  3. Provide a name, and select 'Let me override defaults'

  4. Unselect 'Make this CA the default'

  5. Change the validity period as necessary, I recommend setting this to a longer length (such as 10 years)

  6. Leave the rest of the options, and click Next through the rest of the pages

  7. To verify, click 'Show CA Certificate'

  8. Click Keychain Access, Certificate Assistant, and Create Certificate

  9. Set the Identity Type to 'Leaf'

  10. Set Certificate Type to 'Custom' and choose the certificate authority we created earlier

  11. Override defaults and set the same validity period as you wish

  12. Set the Issuer to your certificate authority you made earlier

  13. Leave the rest of the options, and click Next through the rest of the pages

  14. Delete the private keys for both the certificate authority and the leaf certificate

  15. Right click on the Leaf certificate and press 'Export'

  16. Select the '.cer' file format

  17. Export this and add it to your iOS project (ensuring it's target membership includes your main app)

  18. Right click on the authority certificate and press 'Export'

  19. Select the '.cer' file format

  20. Export this to your project (it's good to keep it in source control) but do not add it to your app target

The leaf certificate is shipped with your application. The authority certificate is what is installed on the device, and is what enables the SecTrustEvaluateWithError call to succeed.

Creating and Installing the Profile

Using the Apple Configurator app, click on File and New Profile. Provide a name and other required details. Under Certificates, click Configure and select the CA certificate exported in step 19. This will generate a profile - you can name it anything.

There are numerous ways to install the profile onto a device. At Sidetrack, we store it in a secure Google drive where we can install it from their mobile app. Though while we've got it open, we'll do it in Configurator. Select your device and click Add. Select your profile and confirm.

Now this adds it to your phone's storage, but you must first install it for it to be trusted. Head to your iPhone Settings, General and then VPN & Device Management. Your custom profile should appear, in which case you can select it, tap Install, enter your passcode, tap Install again and you're done.

At this point the isDebugProfileInstalled computed variable should start passing, and you can use it to unlock functionality in your app.

//
// DebugDevice.swift
//
// Copyright 2022 • Sidetrack Tech Limited
//
import Foundation
// This must be called on the main-thread.
var isDebugProfileInstalled: Bool {
// DebugModeLeaf is generated in Step 16, you may need to change the name.
guard let path = Bundle.main.path(forResource: "DebugModeLeaf", ofType: "cer") else {
return false
}
// We load the certificate into memory and convert it to a certificate type using Apple's Security framework.
guard let data = try? NSData(contentsOfFile: path) as CFData else {
return false
}
let cert = SecCertificateCreateWithData(nil, data)
let policy = SecPolicyCreateBasicX509()
// Create a trust management object; a wrapper around the certificate
var trust: SecTrust?
_ = SecTrustCreateWithCertificates([ cert ] as CFArray, policy, &trust)
guard let unwrappedTrust = trust else {
return false
}
var error: CFError?
// Verify that we can trust the certificate, this will only succeed if the device has the authority profile installed
guard SecTrustEvaluateWithError(unwrappedTrust, &error) else {
// You may wish to do something with the error here...
return false
}
return true
}
@Sherlouk
Copy link
Author

It is important that you keep the Authority Certificate (and configuration profile which contains it) private. This is the literal key to this system, where the Leaf Certificate is the lock.

The Leaf Certificate can be shared, it's completely harmless, and this is why we can safely store it in the app binary (without worrying about somebody extracting it - they can, but can't do anything with it).

At Sidetrack, we keep the Leaf certificate (the lock) in source control and store the Authority certificate (the key) in a secured Google drive only accessible by the company. Keep your keys safe folks!

@tovkal
Copy link

tovkal commented Jan 20, 2023

Having problems on step 10. I choose Custom, it opens a Finder window but the .cer is not selectable. Tried to export it in different formats (p7b, p12, pem) but none work. Could it be that there is some step missing?

@Sherlouk
Copy link
Author

Having problems on step 10. I choose Custom, it opens a Finder window but the .cer is not selectable. Tried to export it in different formats (p7b, p12, pem) but none work. Could it be that there is some step missing?

Have you tried using https://github.com/getsidetrack/swift-device-authority CLI? It automates all these steps for you and has had success in other apps.

These steps were tested and should work however so unsure of the issue.

@tovkal
Copy link

tovkal commented Jan 22, 2023

Having problems on step 10. I choose Custom, it opens a Finder window but the .cer is not selectable. Tried to export it in different formats (p7b, p12, pem) but none work. Could it be that there is some step missing?

Have you tried using https://github.com/getsidetrack/swift-device-authority CLI? It automates all these steps for you and has had success in other apps.

These steps were tested and should work however so unsure of the issue.

Using the CLI worked, made it harder for my monkey brain to mess up. Thanks!

@Sherlouk
Copy link
Author

Awesome, glad that worked for you 😀

definitely raise issues on the above repo if you have any feedback/ideas!

@jbehrens94
Copy link

jbehrens94 commented Mar 20, 2023

Hi @Sherlouk,

Thanks for this awesome write-up! I've got a bit of feedback, nothing big.

  1. isDebugProfileInstalled will provide a purple warning in Xcode when running on the main thread, for line 35.
  2. I'm missing a tiny bit of information in your step-by-step list for Certificate Assistant, sometimes it'll ask if I want to use an existing certificate to sign my self-signed root. That should of course not happen, but might be a good warning to include in the list.
  3. In my case, when I wanted to remove the private keys from Keychain Access, it removed the certificates too. That might be unexpected and I don't think you need to remove the private keys.
  4. I was activating the .mobileconfig file on my iPhone and I noticed that it says not trusted, is that expected?

Again, thank you for this tip!

Best wishes,
Johann Behrens

@Sherlouk
Copy link
Author

Thanks for taking a look @jbehrens94!

I'd definitely take a look at the repository which encapsulates all of this information. It hopefully addresses each of these concerns: it has much better handling for threading (avoiding the purple warning), automates the creation of the profile/certificates (avoiding human error and poor instructions) and I've not had any "Not Trusted" errors.

On the last one, it will say "Not Signed" but shouldn't have any trust issues once you've installed it.

If you have any issues with the repo above, I'd recommend raising issues there and I can look into them for you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment