< Previous PageNext Page > Hide TOC

About Code Signing

Code signing is a technique that can be used to ensure the integrity of code, allow the system to unambiguously determine the source (developer) of the code, and allow any application to determine the purposes for which the developer intended the code to be used. The code signing solution on Mac OS X is intended to be completely managed by the developer. This means that it is up to you to create or purchase and maintain signing certificates, sign your code, specify the meaning of the signature, and distribute the signed code in a way that that is convenient for users. Although the code signing system will carry out policy checks based on a code signature, it is up to the caller to make policy decisions based on the results of those checks. When it is the operating system that makes the policy checks, whether your code will be allowed to run in a given situation depends on whether you signed the code and on the requirements you included in the signature.

This chapter describes the benefits of signing code and introduces some of the basic concepts you need to understand in order to carry out the code signing process.

In this section:

The Benefits Of Signing Code
Digital Signatures and Signed Code
Code Requirements
The Role of Trust in Code Signing


The Benefits Of Signing Code

When code is signed, it is possible to determine reliably whether that code has been modified by someone other than the signer, no matter whether the modification was intentional (by a hacker, for example) or accidental (as when a file gets corrupted). In addition, by adding a code signature, a developer can ensure that updates to a program are valid and can be treated by the system as the same program as the previous version.

For example, suppose the user gives the SurfWriter application permission to access a keychain item. Each time SurfWriter attempts to access the keychain, the keychain must determine whether this is the same application as the one to which the user gave permission. If the application is signed, the keychain (in Mac OS X v10.5 and later) can determine this with certainty. If the developer of SurfWriter updates the program and signs the new version of SurfWriter with the same unique identifier as the old version, keychain will recognize the update as the same application and will give it access without requesting verification from the user. On the other hand, if SurfWriter is corrupted or hacked, keychain will detect the change and will refuse access.

Similarly, if you use Parental Controls (in Mac OS X v10.5 or later) to prevent your child from running a specific game, and that game has been signed by its manufacturer, your child cannot circumvent the control by renaming or moving files on the disk. Parental Controls can use the signature to unambiguously identify the game regardless of its name, location, or version number.

All sorts of code can be signed, including tools, applications, scripts, libraries, plug-ins, and other “code-like” data.

Code signing can be seen as having three distinct purposes. It can be used to:

To enable signed code to fulfill all of these purposes, a code signature consists of three parts:

For more discussion of digital signatures, see the following section, “Digital Signatures and Signed Code.”

To learn more about how the code signature is used to determine the code’s trustworthiness for a specific purpose, see “Code Requirements.”

Note that code signing deals primarily with running code. Although it can be used to ensure the integrity of stored code (on disk, for example), that's a secondary use.

In order to fully appreciate the uses of code signing, it is important to be aware of some things that signing code cannot do:

Digital Signatures and Signed Code

A digital signature uses public key cryptography to ensure the integrity of data. Like traditional signatures written with ink on paper, they can be used to identify and authenticate the signer of the data. However, digital signatures go beyond traditional signatures in that they can also ensure that the data itself has not been altered. This is like designing a check in such a way that if someone alters the amount of the sum written on the check, an “Invalid” watermark becomes visible on the face of the check.

To create a digital signature, the signer generates a message digest of the data and then uses a private key to sign the digest. The signer must have a valid digital certificate containing the public key that corresponds to the private key. The combination of a certificate and related private key is called an identity. The signature includes the signed digest and information about the signer’s digital certificate. The certificate includes the public key and the algorithm needed to verify the signature.

To verify that the signed document has not been altered, the recipient uses the algorithm to create their own message digest and applies the public key to the signed digest. If the two digests prove identical, then the message cannot have been altered and must have been sent by the owner of the public key.

To ensure that the person who provided the signature is not only the same person who provided the data but is also who they say they are, the certificate is also signed—in this case by the certification authority who issued the certificate. Digital certificates are described in Security Concepts.

Signed code uses several digital signatures:

Code Requirements

It is up to the system or program that is launching or loading signed code to decide whether to verify the signature and, if it does, to determine how to evaluate the results of that verification. The criteria used to evaluate a code signature are called code requirements. The signer can specify requirements when signing the code; such requirements are referred to as internal requirements. A verifier can read any internal requirements before deciding how to treat signed code. However, it is up to the verifier to decide what requirements to use. For example, Safari could require a plug-in to be signed by Apple in order to be loaded regardless of whether that plug-in’s signature included internal requirements.

One major purpose of code signatures is to allow the verifier to identify the code (such as a program, plug-in, or script) to determine whether it is the same code the verifier has seen before. The criteria used to make this determination are referred to as the code’s designated requirement. For example, the designated requirement for Apple Mail might be "was signed by Apple and the identifier is com.apple.Mail".

To see how this works in practice, assume the user has granted permission to the Apple Mail application to access a keychain item. The keychain uses Mail’s designated requirement to identify it: the keychain records the identifier (com.apple.Mail) and the signer of the application (Apple) to identify the program allowed to access the keychain item. Whenever Mail attempts to access this keychain item, the keychain looks at Mail’s signature to make sure that the program has not been corrupted, that the identifier is com.apple.Mail, and that the program was signed by Apple. If everything checks out, the keychain gives Mail access to the keychain item. When Apple issues a new version of Mail, the new version includes a signature, signed by Apple, that identifies the application as com.apple.Mail. Therefore, when the user installs the new version of Mail and it attempts to access the keychain item, the keychain recognizes the updated version as the same program and does not prompt the user for verification.

The program identifier or the entire designated requirement can be specified by the signer, or can be inferred by the codesign utility at the time of signing. In the absence of an explicitly specified designated requirement, the codesign utility typically builds a designated requirement from the name of the program found in its Info.plist file and the chain of signatures securing the code signature.

Architecturally, a code requirement is a script, written in a dedicated language, that describes conditions (restrictions) the code must satisfy to be acceptable for some purpose. It is up to you whether to specify internal requirements when you sign code.

Note that validation of signed code against a set of requirements is performed only when the system or some other program needs to determine whether it’s all right to trust that code. The Finder, for example, might run a program that has an invalid code identifier as long as there is no reason to check the identifier. Even if that code requests access to a keychain item and the keychain checks the identifier, the only consequence of the identifier being invalid is that the keychain will refuse access to the keychain item; the process will be permitted to continue running.

The Role of Trust in Code Signing

Trust is determined by policy. A security trust policy determines whether a particular code identity (assuming it is valid) should be accepted for allowing something, such as access to a resource or service. Each Mac OS X component has its own policy, and makes this determination separately. Thus it makes no sense to ask whether the code signing system trusts a particular signature. Instead, it is more meaningful to ask whether a specific subsystem of Mac OS X trusts the signature. Therefore, in general, in order for an application that is signed to be trusted for a particular purpose it must have been signed either by an identity whose root certificate is already trusted by default on Mac OS X or by one that has previously been designated by the caller as being trusted.

Note that many parts of Mac OS X do not care about the identity of the signer—they care only whether the signer has changed since the last time the signature was checked. They use the code signature’s designated requirement for this purpose. The keychain system and parental controls are examples of this use of signatures. Self-signed identities and home-made certificate authorities (CAs) work for this purpose as well as commercial signing certificates.

Other parts of Mac OS X constrain acceptable signatures to only those drawn from certificate authorities (root certificates) that are trusted anchors on the system performing the validation. For those checks, the nature of the identity used matters. The Application Firewall is one example of this type of policy. Self-signed identities and self-created CAs do not work for this unless the validating system has been told to trust them for code signing purposes.



< Previous PageNext Page > Hide TOC


© 2008 Apple Inc. All Rights Reserved. (Last updated: 2008-11-19)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.