Your Apps and the Future of macOS Security

Session 702 WWDC 2018

Apple is on a mission to advance the state of Mac security, and we want your apps to be there with us. Learn about new protections for user data, new capabilities with Developer ID, and how you can best secure your apps.

[ Music ]

All right.

[ Applause ]

My name is Pierre-Olivier Martel.

I'm an engineering manager in the Security, Engineering, and Occupational Group here at Apple.

And today, along with two of my colleagues, I am here to talk to you about some of the new security features in macOS Mojave and how you can make the most of it in your apps.

I'll start by going over some of the high-level security improvements that went into the OS this year.

And then I would like to dedicate the rest of this session to talk about some of the enhancements that we are putting in Gatekeeper.

A few years ago we introduced a feature called Systemic Security Protection to macOS with the goal to increase the protection of the operating system by making it so that platform binaries are protected from modification both on disk and at runtime.

This year we are taking it one step further by enforcing additional code-sending requirements on platform binaries.

The system will now enforce the validity of code signatures throughout the lifetime of system processes and will automatically abort any process that deviates from its code signature or that attempts to execute any code that is not properly signed by Apple.

In addition to that, the system will monitor it - the dynamic loading of any libraries, frameworks, and plug-ins and enforce that - those objects also be signed by Apple.

It's a mechanism that has been enforced on iOS for several years now, and we are excited to make this to be for the macOS.

Of course, not that this only applies to the system.

This does not apply - it does not apply to your apps.

However, there still remains a few system extension points throughout the operating system that have not yet made the move to the app extensions model.

And those are technically considered to be platform binaries; OK, it's the plug-in loaders.

So for those we are going to relax that policy, and the system will still allow these processes to load code that is either third-party signed or completely unsigned.

So if you ship any of these plug-ins in your app, please make sure that you test on the developer preview and make sure it works properly.

If not, please let us know.

Next, I would like to talk about UI automation.

The security model of a macOS, especially when it comes to user data access, relies on the user making security decisions for their self - for themselves.

We deliberately captured those decisions, either via the user intent using the mechanisms like the open/save dialogs or drag-and-drop operations or by a user consent, with more explicit authorization dialogs or asking the user to make security configuration changes in System Preferences.

As such, it's critical for the operating system to be able to differentiate between the user actually making these decisions and software driving the UI on their behalf.

In the past we have made a few targeted enhancements to some of the system authorization dialogs to make sure that they can detect and block these synthetic events.

But these decision points have become so pervasive across the OS that we need a better model.

In macOS Mojave, the system will only allow UI events to be dispatched by processes that the user has specifically configured to control the UI on their behalf and effectively impersonate them.

This configuration is made in the Security and Privacy Press pane in the System Preferences.

And it's currently co-located with the existing accessing to the key list.

This is the list of APIs that will be impacted moving forward.

They mostly fall under two categories.

First, the kidlet [phonetic] Layer: IOHIDPostEvent and the IOHIDSetMouseLocation; and then second, at the CG Layer.

If you attempt to post any CG event or if you create any CG event tab, we are now providing the Listen Only option effectively creating what we call a modifying tab.

And the user will have to approve those processes as well.

And then next, we put a lot of focus of hardening Safari itself.

It is, after all, one of the most important Internet facing applications on the machine.

So it deserves special attention.

In Mojave, Safari, as well as every satellite processes that ship as part of it, it's fully sandboxed.

If you are a web developer, this may potentially have an impact on your local development workflow due to the way that Safari now acts as its local resources on this.

If you want more details, please check out the What's New in Safari and WebKit session this Friday.

And then of course, WebKit has been sandboxed for many years now.

We put a lot of attention in auditing the existing sandboxes as well as removing any risky and unnecessary dependencies from those.

For example, the web content process no longer needs access through the Windows server, to the dock, or to the network.

If your app uses the system WebKit, then there is nothing for you to do in order to adopt this.

You will automatically benefit from those improvements.

Next, I'd like to talk about Gatekeeper.

So Gatekeeper has done a great job over the years in stopping widespread malware attacks on the platform.

It's here.

We would like to make it better.

And we are focusing on three main aspects.

First, I invite Kelly onstage to tell you about a new security mechanism that puts the user in control over the way apps access their personal data.

Then I'll introduce a new security feature that you as a developer can adopt in your apps to increase their security and their transparency.

And then finally, I am sure you are all very impatient to hear more about the Developer ID notary service that Sebastian mentioned in his talk yesterday.

So I invite Garrett onstage to tell you more about that.

All right?

Let's get started.

Kelly?

[ Applause ]

OK, thank you Pierre.

Hi, my name is Kelly Yancy.

I'm with the OS Security Team here at Apple.

And I am really excited today to tell you about the new user data protections in macOS Mojave.

Now in macOS High Sierra, these APIs prompt the user for consent before allowing apps to access their respective data.

With these prompts, well-intentioned software can honor the user's preferences with regards to how they access their personal data.

Well now, in macOS Mojave, access to this data requires user consent even for apps that access the Backing/Store directly via the file system.

Now apps that currently use prescribed APIs to access this data should be well prepared.

But as always, we encourage you to test your apps against the latest macOS release.

Now if your app does access the underlying databases directly via the file system, be aware that that may - that access may now block the calling thread while the operating system presents an authorization prompt to the user.

And in a world where computers do billions of operations per second, it turns out people are relatively high latency.

So you don't want to do that I/O in your app's main thread, or it may appear hung while the prompt is displayed.

So here is an example of code that accesses the user's pictures via the file system.

Now by default, the Photos app stores the user's Photos library in the Pictures folder.

So when this code traverses the user's Photos library, it may now trigger an authorization prompt for access to the user's photos where it would not have in macOS High Sierra.

Now apps that traverse the user's Home folder could trigger multiple approval prompts, not just for photos for contacts, for calendars, and so on as many apps that traverse the entire file system, such as disk management or backup software.

So user can pre-approve such apps by adding them to the new System Application Data category in the System Preferences Security and Privacy pane.

By doing so, the user preauthorizes those apps to access all of their privacy-sensitive data without prompting.

Authorization can also be preconfigured in education or enterprise environments via MDM server as long as it's a user-improved enrollment.

When the user is prompted to authorize access to their personal data, it is important to communicate the purpose of that access.

Imagine that you just installed an app that you had never used before.

And the very first time you launch it, you saw this prompt.

That's a tough decision.

But we can make that decision easier by including purpose text, which makes it clear why the app is requesting access and what the consequences of declining that access would be.

Now your app can specify the text displayed in the authorization prompts displayed on its behalf by including keys in your Info.plist file.

So here are the Info.plist keys for each of the APIs that we have been looking at.

Now you may notice that these are largely the same as on iOS.

I want to call out one difference, and that's the Locations Services Info.plist key.

This key is actually deprecated on iOS, but I assure you it is the correct key to use in macOS Mojave.

So these keys will be required for apps linked against the 10.14 SDK.

So besides informing the user, these keys are also being used to inform the operating system that as the developer you intend for your app to access the user's personal data.

And should an app try to access the user personal data but not include the appropriate key and purpose string for that data, macOS Mojave assumes that that access was unintended and the app exits.

For compatibility, these keys are optional for apps that link - that target older SDKs.

So for example, if you have an app that still targets the 10.13 SDK and tries to access the user's personal data via one of these APIs, the app will not exit but will display a prompt lacking the purpose string like the first one that we saw a minute ago.

So we still encourage you to include the Info.plist keys in your apps, even if you are targeting an older SDK, so that the user is better informed why your app is accessing their data.

So in addition to these prompting categories, macOS Mojave also restricts access to this privacy-sensitive user data as well.

So the operating system will not prompt for authorization to access this data via the file system.

Only the respective system apps or services have access to this data plus any apps that the user has preauthorized for system application data via the Security and Privacy Preference pane that we just saw.

In addition, authorization may be preconfigured via MDM enrollment.

Another way that this data can be accessed is via scripting.

So Mail, Messages, and Safari are all scriptable, exposing some of their functionalities automation by other apps.

Let's use Mail for an example.

Mail's local database contains lots of personal information.

It has the e-mail addresses of my friends, family, companies I do business with.

And then there is the contents of the mail messages themselves my private correspondence, my shopping receipts, my shipping notifications, and my temporary passwords for services I forgot the password of.

So the Mail app necessarily has access to its own local database.

And in macOS Mojave, other apps do not.

But since Mail can be scripted by other applications, we need to be sure that Mail only shares my personal information with my consent.

Because we want the user to be in control of how apps they have trusted with access to their data act on behalf of other apps, macOS Mojave will include prompts like this one, authorizing apps to control other apps.

Now the developer preview does not currently require authorization to automate other apps.

But you can try this new protection out in a future preview.

Only if the user consents will Mail accept being automated by other apps.

So this applies to Apple events.

But there are exceptions.

And there are exceptions for Apple events that are not particularly privacy sensitive for example, opening documents in a default application, opening URLs in the default handler for that URL scheme, or opening other applications.

Finally, macOS Mojave brings every one of my favorite features from iOS.

User authorization for camera and microphone: I think I am going to decline this one.

So apps can - that's not a link in [inaudible] - apps can enumerate the camera and microphone hardware without user consent.

But initiating capture requires user authorization.

And this applies to all devices supported by the built-in drivers.

Now your app can query the authorization status.

And this is useful if you'd like your app's user experience to reflect user's previous decisions.

And this API provided by AVFoundation is the same as on iOS.

And what's interesting is it doesn't just return a simple Boolean yes/no.

It actually returns an enumeration of four possible values.

And I'd like to drill down on those because I think these are relevant.

The first one, notDetermined, means that the user has not previously been consented for your app to access the camera or microphone.

So should your app try to access that hardware, the operating system will display a prompt at that time.

The restricted value actually means that the user cannot consent, that the hardware the camera or microphone has been disabled the parental controls or mobile device management.

The denied value means the user has previously been prompted, but the user declined to give consent.

They don't want your app to access that hardware.

And finally, the authorized value means that the user has previously been prompted, and they did consent and your app can access that hardware.

So we believe it's important to prompt in context.

And this is the reason why the operating system currently displays the prompts kind of just in time.

At the moment that your app accesses the microphone of the camera, the operating system will present a prompt when necessary.

And we feel that that's the right time because the user has the most context to understand why your app is accessing the hardware.

But there are times where your app might want more control over the timing of those authorization prompts.

For example, if your app opens a new window, and in that window displays frames from the camera or a visualization of the audio from the microphone, you might want to avoid displaying an empty window if the user declines authorization in which case it's better to prompt before opening the window.

So AVFoundation provides this API so that you can preflight that authorization.

And I'd like to call out that this API is actually asynchronous.

It takes a block with - that is called with a Boolean value of whether your app has access or not.

So this is a little bit different than the enumeration that we just saw.

That block may be invoked immediately when you make - when your app makes this call.

For example, if the user has previously already consented or denied access, the operating system already knows that answer and can immediately invoke the block telling you what that answer is.

Similarly, if the parental controls or MDM server has made that hardware unavailable, the callback is immediately invoked with a Boolean value of fault.

But it's also possible that this callback will be invoked later possibly much later as a prompt is displayed while we are waiting for - and then only when the user makes their decision will this callback actually be invoked.

At that time we will know the Boolean "Yes your app has access" or "No it doesn't."

So your app can include purpose text for both the camera and microphone.

And as with the other purpose strings, these are required for apps linked against the 10.14 SDK, and optional and certainly encouraged because they are informative for apps linked against earlier SDKs.

So to recap: Here is an overview of all the topics that we just looked at.

macOS Mojave does not solicit user approval for access to this user data.

Only the respective system apps and apps the user has preapproved via the Security and Privacy Preference pane, or preconfigured the parental controls or MDM are permitted to access this data.

And here are the categories of user data and devices the apps may access with user consent.

Now the operating system macOS presents the authorization prompt to the user the first time the app accesses this data.

And then it remembers the user's decision.

And this is great for users because then they only see one prompt per app per piece of data.

They don't get multiple prompts.

But as a developer, you may actually want to get pre-prompted so that you can test how your app behaves while the prompt is displayed, if the user consents, and if the user declines authorization.

So for that purpose macOS provides a tool, called tccutil, that you can use to make the operating system forget your previous answers to consent prompts.

So the next time that you run your app, and your app requires authorization, the operating system will re-prompt.

So this tool is provided for testing purposes only.

Your app should not invoke this tool automatically, even in debug builds.

So in summary, ensure your approval prompts are presented in context.

This is important so that the user understands why they are being prompted.

And add Info.plist keys so the user understands what your app is going to do with the data and what functionality will be unavailable if they decline.

Access approval-gated resources from threads other than the main thread so that your app doesn't appear to be hung while waiting for approval.

And gracefully handle failure to access approval-gated resources in the event that the user does decline.

But finally, when the user does consent, be responsible with the user's personal data.

So these are the new user data protections available in macOS Mojave.

Thank you, and I will turn the stage back to over to Pierre to tell you about the enhanced runtime protections.

[ Applause ]

Thanks Kelly.

So in the few years since the maturity of system integrity of protection to the Mac, a lot of you have asked us what you could do in your apps to adopt some of the runtime protections that we afford to the rest of the system.

Until now, there wasn't really a good story for this.

Today, we are introducing a new set of runtime protections that you can easily adopt within your app.

It is a new opt-in mechanism that is available within the 10.14 SDK.

It effectively sets a new security baseline for your app by enabling the full set of runtime protections that the system provides, and requiring you - requires you to opt to back into more risky behaviors or ideas.

It is easily configurable with a new set of unrestricted entitlements.

Unrestricted here means that these entitlements are available to everybody without any prior approval.

It can be easily configured from within the Xcode UI.

And then finally, it is fully backward compatible if you need to be able to deploy your app to older releases of macOS and its version.

So as we add more features to this one time in the future, apps that have already shipped will not be impacted.

Now let's see what - let's talk about these new protections.

First off, code signing: When you opt into this new runtime, the system will enforce that every single executable page within your address space must be backed by the original code signature that shipped with your app.

It is a fine behavior for most apps out there.

Of course it might be undesirable in some of these cases.

So let's see how we can configure this.

Let's say, for example, that your app has a scripting runtime for which you have high-performance requirements in which case, you'll most likely use JIT compiled code if you want to execute a runtime.

With this, you can use the first entitlement in this list.

It gives you access to the new MAP JIT flag in the MMAP system call, which allows you to create what we call JIT regions, which are memory regions that are readable, writable, and executable.

And if you have a poliacre [phonetic] system, where you might expect to be able to execute load plug-ins that are not properly signed or not signed at all, then you have to use the second entitlement in this list.

And finally, if your app needs the ability to modify its own code pages at runtime, effectively breaking its own code signature, then you will have to use the last entitlement in the system.

And note that the vast majority of apps should not need that functionality.

But we still want it to operate anyway.

Next, library validation: When you opt into the new runtime, the system will enforce the code signature of every library, framework, and plug-in that you dynamically load at runtime, and by default will enforce that.

These modules have - these objects have to be signed by Apple and shipping as part of the OS or that they be signed with the same Team ID as the main executable that ships with your app.

If you have a plug-in ecosystem here and you need the ability to load objects that are signed by another team, you can use this entitlement to relax that policy.

Note that it still requires you to load signed code; it just can be signed by other teams.

If you need the ability to load fully unsigned code, you will need to use one of the entitlements from the previous slide.

Next, debugging: Apps that are opting into the new runtime cannot be debugged and cannot debug other apps.

If you need the ability to debug your app while it's opting into the new runtime, you can use the get-task-allow entitlement.

Note that Xcode will automatically add this entitlement for you when you hit Build and Run from Xcode.

So if you use Xcode as part of your local development workflow, then you don't need to do anything.

Executable will also make sure that the entitlement is properly stripped from your signature when you do an export for distribution.

If you don't use Xcode, make sure you don't ship your app with this entitlement unless you really need it.

If your app is actually a debugger, then you will use the second entitlement in the list.

And then finally, in the few rare occasions where your app needs to rely on the DYLD environment variables to modify its BFU [phonetic] at runtime, then you can use the last entitlement in this list.

And finally, your resource access: This runtime requires you to be transparent about the kind of data classing that your app needs to access.

So if your app attempts to access any data that is part of one of the protected categories that Kelly described in his previous section, and you don't have the appropriate entitlement signed in your app, then the system will automatically terminate it.

We have entitlements that map to every single category that Kelly described.

But remember that just adding this entitlement is not enough.

You also need to add a purpose string if you are linking against the 10.14 SDK.

And finally, it does not automatically grant you access to the data.

The user is still in control of the final decision.

So how do we enable this?

Well, from Xcode you can go into Target setting in the Tap-ability tab.

There you will find a new hard and Runtime section, which you can enable.

We have checkboxes for every single of the entitlements that are previously described.

And then a few more comportable [phonetic] using the using the Command Line interface, then we can use the new runtime option in the codesign command.

And in order for you to validate that you have properly enrolled and opted into this new runtime, you can use the dash-dash display option.

And here, the things to look for are the runtime flag as well as the runtime version.

All right.

Now let's look at the final piece of that puzzle and talk about notarized apps.

Garrett?

[ Applause ]

Thanks Pierre.

Hi everyone.

I'm Garrett, and I work on the Trusted Execution Team here at Apple.

Now my colleague earlier, Kelly, talked about one way we help protect users from malicious software by ensuring the user is always in control of their private data.

I'd like to talk about another way that we protect users from malicious software.

And that's by identifying and blocking malicious software so it doesn't have the chance to run.

Now the Mac App Store is a great place for users to find and download new software.

And people can confidently install apps knowing that Apple has taken steps to ensure they are not harmful.

Now the Mac App Store is getting a lot of attention this year, and that's great.

But we also understand that some developers need the flexibility of the Developer ID program.

Together, Gatekeeper and Developer ID have done a great job of preventing widespread outbreaks of malicious software.

And today, we are making the Developer ID program even safer with the introduction of app notarization.

Now app notarization is a process designed to help identify and block malicious software before distribution while still maintaining all the flexibility of the Developer ID program.

That means that you can continue to ship your apps the way you do today with the same capabilities that they have today.

And the key to this is the Develop ID notary service.

Now the notary service is an automated service that performs security checks of Developer ID signed content.

It's an optional extension to the Developer ID program, and it's not an app review.

Starting today, developers can start uploading distribution-ready content to the notary service.

And assuming that those applications, installer packages, and disk images don't contain any malicious software, the notary service will issue a notarization ticket back to your application.

That ticket can be stapled and then distributed alongside your application.

And when Gatekeeper launches a notarized app for the first time, it can verify the notarization and provide a new first-launch experience.

Now your development workflow prior to distribution is completely unchanged.

Now you may have heard, in the State of the Union, that this process will be required in the future.

And while that's true, for now notarization is completely optional while we roll the service out and listen to feedback.

Before we move on, I want to make one important point.

This is not an app review.

The notary service is simply performing a set of security checks to ensure that your content can be distributed safely.

So what does this actually look like for your development workflow?

Well here's a high level and simplified overview of the development process.

Over on the left, a developer iterates on an application local to their system building features, debugging, and signing with their Mac Developer certificate.

When the application is ready for release, it's signed with the Developer ID certificate, and a final test task can be performed.

After that, the content can be distributed directly to users who can run it or Gatekeeper can verify that it wasn't tampered with; and the user gets to run your application.

For this app to be notarized, only one additional step is required.

You continue to develop locally, just like before.

And once you sign it with your Develop ID certificate, a copy can be uploaded to the Apple notary service.

Assuming that the Developer ID content doesn't contain anything malicious, a ticket will be issued back that can be attached to the content through a process we call stapling.

And then the stapled content can be distributed just like before.

And when it ends up on a user's system, Gatekeeper will verify notarization and provide the new first-launch experience.

Now because this is a highly automated process, we are targeting providing tickets back within an hour.

But we'll be working to improve the speed and quality of the service as we roll it out.

So let's talk a little more about those security requirements I mentioned earlier.

Well, first and foremost, no malicious software.

If the security check finds anything malicious inside of the Developer ID signed content, it will immediately create a special kind of ticket called a revocation ticket and immediately notify the developer.

Second, all executables need to be properly code signed.

And this is important to make sure that when the application ends up on a develop - on a user's system, Gatekeeper can verify that it wasn't tampered with.

And finally, all binaries must opt into the enhanced runtime that Pierre described earlier so they can benefit from the additional protections of the operating system without reducing their capabilities.

So assuming that you have an app that's ready for notarization, how do you actually go about uploading it?

Well, it's built into the Archive and Distribution workflow inside of Xcode.

So if you already use that, you are pretty much set.

Here you can see the Archive pane of the Organizer.

And I have the Watch Grass Grow app already archived.

So I click the Distribute App button on the right.

I'll be taken to my distribution options.

I'll continue to distribute it via Developer ID just like I have in the past.

And when I select that, I'll have a new option to upload to the notary service.

Clicking Next will show a progress bar while the Developer ID content is uploaded to the notary service.

And as soon as the upload is complete, you'll be notified that notarization has started.

From here you can export a copy of your app to perform any local testing that you might want to do in parallel.

And if you click Close, you'll be taken back to the Archive pane; and you can see that the status has switched to Processing.

When notarization is complete, a push notification will arrive and Xcode will notify you that notarization is done.

Xcode will then automatically download the ticket, staple it to your content.

So the next time you go into the Archive pane and click Export, you'll already have a stapled Developer ID notarized application.

And when the user launches it for the first time, they'll see a new version of the first-launch dialog that includes your app's icon.

Now we understand that not everybody uses Xcode's distribution workflow, although this Xcode works - dah.

The Xcode workflow is available today in the preview.

We have also built a set of command line tools to perform every step of this so that you can integrate them with any custom flows [phonetic] you have.

And the first step is to upload a copy for notarization.

Now the notary service accepts Zip files, installer packages, and disk images.

So if you have a bare application, you'll need to zip it up prior to uploading to the notary service.

The tool for working with the notary service is altool.

Here you can see a command line indication sending the Watch Grass Grow image up for notarization.

Note that altool does require authentication, but you can pass in your credentials via Environment Variables or the key chain.

Once upload is complete, you'll get a UUID that can be used to monitor status of processing.

But you can also turn back and pass the altool to check on the status of your notarization.

Here we see another command line indication of altool to just check the status of notarization.

And then you can see here that notarization was complete, was successful.

And importantly, there is a log file that comes back from the notarization service.

This is a great place to check for any warnings, or it tells you exactly what was included in your notarization ticket.

So you can make sure that everything in your package was notarized properly.

And the last step before you distribute content is to staple your notarization ticket to whatever content you are going to distribute.

Now we have a special tool for that called Stapler.

Now you can staple tickets directly to applications, disk images, and installer packages.

And Stapler combines both retrieving the ticket and attaching it to the content in one easy step.

Here you can see I am stapling the ticket directly to this image.

After that's done, I can distribute the disk image, and the users will already get a notarized application.

So as a quick reminder, in macOS Mojave, for non-notarized apps we'll continue to keep the first-launch dialog that Gatekeeper has always had for Developer ID applications.

For notarized applications, they'll get a new version of this dialog that prominently displays the app's icon.

And if the user does manage to download software that has malicious content in it, the content won't run, and they'll be treated to this warning.

Now this is not a new capability; macOS has always had the capability to block applications like this.

But notarization does allow us to identify specific malicious content earlier and provides a much better experience than if a developer needs to revoke their entire Developer ID certificate.

So that's how to build notarized apps and how they are going to help keep Mac users safer.

What can you do?

Well, the notary service is available today.

So feel free to start uploading your applications.

And there is no reason to wait for your next app update.

The service will gladly check your back catalog, too.

So send in anything you have got.

We are looking for feedback while we roll the service out.

So if you have any issues with notarization, please come to the labs and we'd love to work through them with you.

Remember that signing issues, for now, will be warnings but are going to become errors in the future.

And when macOS Mojave ships later this year, Gatekeeper will be highlighting notarized applications to users.

But then in a future macOS release, Gatekeeper will be requiring notarized apps by default.

And that's all for Gatekeeper.

So now I'd like to hand it back to Pierre for some closing words.

[ Applause ]

Thank you Garrett.

All right, let's look at the key takeaways from this session.

First, the macOS Mojave, the user is now in control over the way apps can access their personal data.

It means your app needs to be ready to handle their decisions first, because the user make take a while before they actually give you an answer.

Second, because they might completely decline the request.

Additionally, please be transparent to the user about what did I need to access and why you need to access it, using new entitlements and purpose strings for this effect.

Also, make sure you request access to this data in context in the context where the user can actually understand why you need it and is more likely to grant you this request.

We have a new higher runtime, which you can adopt in your app today.

It effectively increases the security and the transparency of your app.

It does not take away any of the capabilities that you have today.

It just requires you to opt into them.

And finally, please help us make our users feel more secure and stop malware as soon as possible by getting your apps notarized.

The Developer ID notary service is open for submission right now.

If you need more information about this session, please check out our developer website.

We have a lab immediately after this section from 3:00 to 6:00 and then another lab tomorrow from 9:00 to 12:00.

And finally, there will be another lab on Thursday dedicated to signing and distribution.

Again, thank you very much for coming.

Hope you have a great rest of the week.

[ Applause ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US