Go to:OBJC ChinaAnalysis of Code signatureDOPCN Oct Share Articles
"Users will appreciate the benefits of code signing" –apple Developer Library:code Signing Guide
Most of the APIs you need to use for app development on IOS or OS X platforms are designed to be simple and straightforward. You can easily perform cool animations, make app pre-release tests easy, or store your data securely locally with Core. But someday, you'll run into code signing and configuration files (provisioning), and in most cases this will be the beginning of your heart greeting to some people's ancestors.
If you've already developed an app on IOS, you've probably already dealt with code signing or device configuration files. Even for OS X developers, if you want to publish your app to the Mac app Store or want to participate in the Apple Developer project, you'll have to start signing your own code.
Most of the time the code signature looks like a mysterious black box that's hard to understand. In this article I will try to reveal the inner workings of the box as much as possible.
In general, we cannot directly see the process of code signing, which is hidden inside the IOS system and within the SDK. But we can find some clues by observing how the tools needed to set up code signing work. In addition, we can refer to how the code signature works on OS X, after all, IOS and OS X are homologous, and we can get a lot of useful information from their comparisons.
The code signing technology on OS X and the corresponding API first appeared on Mac OS X Leopard 10.5, just when the first IPhone was released. This is no coincidence, because on IOS, code signing plays a more important role. The IPhone is the first large-scale sale of a number of game consoles and starts with code signing from scratch. IOS can run unsigned code only after the jailbreak. Jailbreak allows an app to bypass the full limitations of code signing and sandbox security, which can be a very risky behavior.
Certificates and Keys
As an IOS developer, you should already have a certificate, a public key, and a private key on the machine you are using for development. These are the core of the code signing mechanism. Like SSL, code signing relies on a public key encryption with the standard.
On OS X, the basic components of the X. (Translator Note: certificates, etc.) are managed by a tool called Keychain access. Open the Keychain Access app on your development machine, select "My certificate (My certificates)" Under the Category option, and you can see all the certificates that correspond to the private key you hold. To set up code signing with a certificate, you must have a private key, so all certificates that you have the private key will be listed here. If you have a private key for a certificate, you can expand the certificate and display its private key:
If you want to export a certificate, for example for backup (strongly recommended), be sure to remember to expand the certificate to show the private key and select both lines.
There is also a way to quickly display the authentication you can use to sign code in your system, using a wide range of command-line tools security
:
$ security find-identity -v -p codesigning 1) 01C8E9712E9632E6D84EC533827B4478938A3B15 "iPhone Developer: Thomas Kollbach (7TPNXN7G6K)"
In summary, a certificate is a public key plus a lot of additional information, these additional information is signed by a certification authority (Certificate Authority CA) for signature authentication, the information in the certification of this certificate is accurate. For IOS Development, this certification body is Apple's certification department, Apple worldwide Developer relations CA. A certified signature has a fixed expiration date, which means that the current system time needs to be set correctly because the certificate is checked based on the current time. This is one of the reasons why setting system time to the past can cause multiple damage to IOS.
For IOS development, there are typically two certificates: one with a prefix iPhone Developer
and the other with a prefix iPhone Distribution
. The former is used to enable the app to run on your test device, which is used when submitting the app to the App Store. The purpose of a certificate depends on the internal information it contains, double-click in keychain Access to open a certificate file, you can see a number of detailed entries, drag to the bottom of a tag Apple Developer Certificate (Submission)
, or Apple Developer Certificate (Development)
, depending on which type of certificate you open, IOS The system uses this information to determine whether your app is running in development mode or publishing mode, and is judged to switch application run rules accordingly.
In order for a certificate with a public key to work, we need a private key. The private key is useful when you are signing a binary file that makes up your app. Without a private key, you can't sign anything with a certificate and public key.
The signing process itself is done by the command-line tool codesign
. If you compile an app in Xcode, it will automatically invoke the command to sign after the app is built, and it codesign
codesign
gives you a lot of formatting-friendly and useful error messages. You can set up code signing information in Xcode's project settings.
It is important to note that Xcode only allows you to choose among a limited number of options, which are certificates that you have both a public key and a private key. So if you don't see the one you want in the options, the first thing you need to check is whether you have the private key of the certificate. Here you need to separate for dev testing or for release, if you want to test your app on the machine, you need to sign it with the pair of keys used for development testing, if you're publishing an app, whether it's for testers or publishing to the app Store, You need to sign with the key that you use for publishing.
All along, these are all the code signatures need to be set up, and these are almost done.
However, the option to set the profile appears in Project settings for Xcode 6. If you select a configuration file, you must select the key pair that corresponds to the public key contained in the certificate for this profile, or you can choose to have Xcode automatically complete the correct settings. We'll explain this in more detail later on, first, or back to code signing.
The composition of a signed application
The signature of a signed executable is contained in the Mach-o binary file format, and for non-mach-o executables, such as scripts, are stored in the extended properties of the file system. This practice allows any executable binaries on OS X and IOS to be signed: whether it's a dynamic library, a command-line tool, or a. App suffix package. This also means that the process of setting up the signature actually changes the file contents of the executable file and writes the signature data to the binary file.
If you have a certificate and its private key, it codesign
is very easy to set up a signature, and we will now try to sign it with the certificate listed below Example.app
:
$ codesign -s ‘iPhone Developer: Thomas Kollbach (7TPNXN7G6K)‘ Example.app
This tool is useful if you want to re-set the signature for an app package. In order to re-set the signature, you must take the -f
parameter, and with this parameter, codesign
you will replace the one that already exists with the signature of your choice:
$ codesign -f -s ‘iPhone Developer: Thomas Kollbach (7TPNXN7G6K)‘ Example.app
codesign
You can also provide you with information about the status of an executable file's signature, which can provide great help when an unknown error occurs. For example, $ codesign -vv -d Example.app
some Example.app
information about the signature is listed:
Executable=/users/toto/library/developer/xcode/deriveddata/example-cfsbhbvmswdivqhekxfykvkpngkg/build/products /debug-iphoneos/example.app/example identifier=ch.kollba.example Format=bundle with Mach-OThin(arm64) Codedirectory v=20200 size=26663 flags=0x0 (None) hashes=1324+5 location=embedded Signature size= 4336 authority=iphone Developer: thomas kollbach (7tpnxn7g6k) Authority= Apple Worldwide Developer Relations Certification Authority authority=apple Root CA signed Time=29.09.2014 22:29:07 info.plist entries=33 teamidentifier=dzm8538e3e Sealed Resources version=< Span class= "Hljs-number" >2 rules=4 files=120 Internal Requirements Count=1 size=184
The first thing you need to see is the Authority
three lines at the beginning. These three lines tell you exactly which certificate has a signature set for this app. Here of course is my certificate iPhone Developer: Thomas Kollbach (7TPNXN7G6K)
. My certificate is signed by the certificate Apple Worldwide Developer Relations Certification Authority
, and so on, the certificate is set by the certificate Apple Root CA
signed.
It Format
also contains some information about the code: it's not Example.app
just an executable file, it's a package that contains a binary arm64
file. From Executable
the path in the information you can see, this is a test for the purpose of packaging, so is a binary Mach-O thin
file.
Two very interesting entries are included in a bunch of diagnostic information. Identifier
is the bundle identifier I set up in Xcode. TeamIdentifier
used to identify my workgroup (the system uses this to determine if the app was published by the same developer). This identity is also included in the certificate used to publish the app, which is useful for distinguishing between different certificates under the same name.
Now the binary file has been signed with a certificate. Just as the medieval man sealed the envelope with wax, the signature sealed the application. Let's check to see if the seal is intact:
$ codesign --verify Example.app$
Just like most UNIX tools, there is no output to represent that the signature is intact. Then I'll break the seal below, just modify this binary file:
$ echo ‘lol‘ >> Example.app/Example$ codesign --verify Example.appExample.app: main executable failed strict validation
Modifying an application that has already been signed destroys the seal, and from the command line we can see that the code signature works as expected.
Packages and other resource files
For command-line tools and scripts, only one executable file is set to sign, but IOS and OS X applications and frameworks contain the resources they need. These resources include images and different language files, and resources include important application components such as xib/nib files, archive files (archives), and even certificate files. So when you set a signature for a package, all the resource files in the package are also set to be signed.
To achieve the purpose of setting up a signature for all files, the signature process creates a new named file in the package that stores the signatures of all the files in the _CodeSignatue/CodeResources
signed package. You can view the signature list file yourself, which is just a plist format file.
This list file contains not only a list of files and their signatures, but also a set of rules that determine which resource files should be signed. With the release of OS X 10.10 DP 5 and 10.9.5, Apple changed the format of the code signature and changed the rules about the resources. If you use 10.9.5 or a later version of the codesign
tool, CodeResources
there will be 4 different areas in the file, which rules
files
are prepared for the old version, files2
and for the rules2
new second edition of the Code signature. The main difference is that in the new version you will no longer be able to exclude certain resource files from the code signature, in the past you can, as long as you add a file named in the package that is signed, ResourceRules.plist
this file will specify which resource files should be ignored when checking that the code signature is intact. However, in the new version of code signing, this practice is no longer valid. All code files and resource files must be signed and no longer have exceptions. In the new version of code signing, an executable package in a package, such as an extension (extension), is a standalone individual that needs to set a signature and should be treated separately when checking whether the signature is complete.
Authorization mechanisms (entitlements) and configuration files (Provisioning)
So far, we have assumed that all certificates play the same role, and assume that if we have a valid certificate code signature it will be effective. However, this is certainly not the only rule. The operating system has many criteria to detect whether your code is allowed to run.
These standards are not immutable. For example, if an application on OS X is allowed to be enabled is determined by the Gatekeeper option, you can change the options in the security options set by the system. Selecting "Trusted developer or from Mac app Store" in the Gatekeeper option requires that an app that is opened must be signed by a certificate, which can be an app publishing certificate for a MAC app Store developer or a developer ID certificate. These options are managed by a system tool spctl
that manages all of the system's security assessment policies.
The rules are different on iOS, and neither the user nor the developer can change the app opening policy, and you must have a developer account or app publishing certificate to run the app on the iOS system.
Even if you can get your app up and running, what your app can do on IOS is still restricted. These restrictions are sandbox-managed. The sandbox and code signing mechanisms are different, which is important. Code signing guarantees that the application contains as little as it says, while the sandbox restricts the resources that the application accesses to the system. These two technologies work together to help prevent your application from running, as well as to cause strange problems in Xcode. But in the daily development process, the sandbox may cause problems more often. When does the sandbox mechanism cause problems, in most cases it is determined by a mechanism called authorization.
Authorization mechanism
The authorization mechanism determines which system resources are allowed to be used by an application under what circumstances. Simply put, it is a sandbox configuration list that lists which behaviors are allowed and which are rejected.
It is likely that you have guessed that the authorization mechanism is also listed in the plist file format. Xcode will pass this file as the --entitlements
content of the parameter codesign
, the internal format of this file is as follows:
<?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" ><Plistversion="1.0" ><Dict><Key>application-identifier</Key><String>7tpnxn7g6k.ch.kollba.example</String><Key>aps-environment</Key><String>development</String><Key>com.apple.developer.team-identifier</Key><string>7tpnxn7g6k</String><Key>com.apple.developer.ubiquity-container-identifiers</Key><Array><String>7tpnxn7g6k.ch.kollba.example</String></Array><Key>com.apple.developer.ubiquity-kvstore-identifier</Key><String>7tpnxn7g6k.ch.kollba.example</string> < key>com.apple.security.application-groups</key> <array> << Span class= "Hljs-title" >string>group.ch.kollba.example</ string> </array> <key>get-task-allow</key> <true/></ dict> </plist>
After you select some options under the Capabilities tab of Xcode, Xcode generates such an XML. Xcode automatically generates a .entitlements
file and then adds an entry to it when needed. When the entire application is built, this file is also presented codesign
to the reference that is required to be licensed as an application. These authorization information must be enabled in the developer Center App ID and included in the configuration file, which we'll discuss in more detail later. The authorization file that you need to use to build your app can be set in the code signing entitlements in Xcode build setting.
In this app I enabled icloud key-value pair storage (Key-value storage) com.apple.developer.ubiquity-kvstore-identifier
, as well as icloud document storage ( com.apple.developer.ubiquity-container-identifiers
). I also added the app to an app Group (for example, to share data with the extension (extensions) com.apple.security.application-groups
), and finally the push feature was turned on ( aps-environment
). This is a development version and I will have the need to connect it to the debugger, which needs to be get-task-allow
set to true
. In addition, the app ID, which is the bundle ID plus the developer ID, is also listed separately.
Of course you are not authorized to do whatever you want, and there is a specific provision for your application to be able to obtain an authorization. For example, when get-task-allow
set to ture
, the app can only run under the certificate signature used for development. Similar restrictions apply to the push environment (aps-environment) that you are allowed to use.
Depending on the operating system version, our optional licensing items are different, so it's difficult to have a list of all the entries in detail. At a minimum, all of the features mentioned in document Adding capabilities need to be authorized.
The authorization information is included in the application's signature information. If you're having trouble with this, you can try to see what authorization information is specifically included in the signature message: $ codesign -d --entitlements - Example.app
A list of attributes that is similar to the previous XML format is listed. You can add the contents of this file to a script, and each time you build the app, use a script to check that the push service is working properly by checking to see if it contains the authorization information for the drive. Here the push service is just an example, the more services you use, the more you add a push notification authorization to ensure that you can register for push notifications. After the new version of Xcode 6, the list of authorized information is Example.app.xcent
included in the app package as a file of that name. In my opinion, this is done to provide more useful error information when a configuration error occurs.
Configuration file
There is one component in the entire code signing and sandbox mechanism that links the signature, authorization, and sandbox, which is the configuration file (provisioning profiles).
Every IOS developer may have spent quite a lot of time researching how to set up a configuration file, which is where it often goes wrong.
A configuration file contains information that the system uses to determine whether your app is allowed to run, which means that if you have a problem with your profile, it can be quite annoying to fix it.
A configuration file is a collection of information that determines whether an application can run on a particular device. Profiles can be used to enable applications to be run and debugged on your development device, or for internal testing (AD-HOC) or enterprise application publishing. Xcode will package the profile you selected in Project setting into your app. As mentioned earlier, the selection profile is a feature provided by Xcode 6, and in Xcode 5 or earlier, the profile was chosen by Xcode based on the signing certificate you chose. In fact, the same certificate can have many different profiles, so let Xcode choose the possibility of some uncertainty, the best way is that you choose, in Xcode 6 finally provide this feature.
Let's take a closer look at the configuration file below. If you want to find the configuration file on your own machine, in this directory ~/Library/MobileDevice/Provisioning Profiles
. Xcode will place all the profiles downloaded from the Developer Center.
Don't be surprised, the profile is not a plist file, it is a file encrypted according to the password message syntax (Cryptographic message Syntax) (hereinafter referred to as the CMS, but do not use this shorthand Google, this is not a good keyword). If you've worked with S/MIME messages or certificates, you'll be familiar with this encryption, and you can see the RFC 3852 developed by the Internet Engineering Task Force (IETF) for more information.
Using the CMS format for encryption allows the configuration file to be signed, so the file cannot be changed after Apple gives you the file. The signature of the profile and the signature applied are not the same thing, it was set up directly by Apple in the developer Center (Developer portal).
Some versions of OpenSSL can read this format, but OS X does not have that version. Fortunately, the command-line tool security
can also decode this CMS format, so we'll use it security
to see .mobileprovision
what the inside of a file looks like:
$ security cms -D -i example.mobileprovision
This command outputs the contents of the signature message, and if you try it yourself, you will then get an XML-formatted plist file content output.
The contents of this list are the configuration information that IOS uses to determine if your app can run on a device, and each profile has its own UUID
. Xcode uses this UUID
as an identifier to record which profile you chose in build settings.
First of DeveloperCertificates
all, this is a list of all certificates that can be signed for an app that uses this configuration file. If you sign a certificate that is not in this list, the app will not work, regardless of whether the certificate is valid. All certificates are based on BASE64 encoded in PEM (Privacy enhanced Mail, RFC 1848) format. To view the details of a certificate, copy and paste the contents of the encoded file into a file, as follows:
-----BEGIN CERTIFICATE-----MIIFnjCCBIagAwIBAgIIE/IgVItTuH4wDQYJKoZIhvcNAQEFBQAwgZYxCzA… -----END CERTIFICATE-----`
Then let OpenSSL handle it openssl x509 -text -in file.pem
.
Go back to the configuration file and you may notice that Entitlements
all the authorization information for your app is included in an item, and the key value is exactly the same as what you saw earlier in the authorization section.
These authorization information is set in the app ID when you download the profile in the developer center, ideally this file should be the same one that Xcode used to set the signature for the app, but this synchronization is not guaranteed. The inconsistency of this file is one of the more difficult problems to find.
For example, if you add the ICloud key-value-to-store authorization () in Xcode, com.apple.developer.ubiquity-kvstore-identifier
but don't update, reset and download the new profile, the old profile specifies that your app does not have this authorization. Then if your app uses this feature, IOS will reject your app from running. This is also the reason that when you edit the app's authorization in the Developer Center, the corresponding profile is marked as invalid.
If you open a certificate for development testing, you will see an entry ProvisionedDevices
that contains a list of all the devices that can be used for testing. Because the configuration file needs to be signed by Apple, every time you add a new device, you re-download the new profile.
Summary
Code signing and configuration files This is probably one of the most complex issues that an IOS developer has to deal with after coding. Unlike running your code directly on a MAC or PC, dealing with these issues can be a very different experience.
While it's helpful to know how each part works, it's really time-consuming to control all of these settings and tools, especially in a development team, where it's obviously inconvenient to send certificates and configuration files everywhere. Although Apple has tried to improve in the last few releases of Xcode, I'm not sure that every change has a good effect. Handling code signing is a big hole for every developer.
While handling code signing is cumbersome for developers, it is undeniable that it makes IOS a very secure operating system for users. If you pay attention to security-related news, every time you see a trojan or malicious software that you can run on IOS, such as a less-famous FinFisher, take a closer look at the detailed instructions, which will say "jailbreak required". To be honest, I haven't seen a virus or trojan that's not jailbreak-oriented for IOS.
So these cumbersome settings for code signing and configuration files are not futile.
More articles under the topic #17
Original Inside Code Signing
About translator DOPCN
@dopcn do non-willful programmers
Http://weizhou.name
©2015 OBJC China
This site is created by the @onevcat, the article originates from Objc.io, and is organized and maintained by OBJC China project team.
Analysis of "Turn" code signature