Skip to content

Commit 302f91e

Browse files
App Check: App Attest provider (#8133)
* App Attest provider: attestation sequence (#7971) * App Attest provider: attestation sequence (#761) * App Attest draft WIP * FIRAppAttestProvider initializers * ./scripts/style.sh * FIRAppAttestProvider implementation draft * Basic FIRAppAttestProviderTests and fixes * style * testGetTokenWhenAppAttestIsNotSupported * More FIRAppAttestProviderTests * Cleanup * Remove unused file * Availability annotations on DCAppAttestService category. * Guard FIRAppAttestProvider with #if TARGET_OS_IOS * Formatting * Fix SPM * app_check.yaml: Add diagnostics SPM builds * fix yaml * Fix Firebase-Package scheme bad merge * Fix typo * FIRAppAttestProvider: hide default init * FIRAppAttestKeyIDStorage: methods placeholders * Comments * Fix updated block definition * Implement app attest key ID storage (#8014) * Implement FIRAppAttestKeyIDStorage * Add FIRAppAttestKeyIDStorageTests * Review [Draft] * Style * Docs updates * Docs updates 2 * Review [Draft] 2 * Improve tests * Improve test readability * Improve test readability 2 * App Check App Attest workflow updates: initial handshake (#8032) * Handshake adjustments (WIP) * Introduce FIRAppAttestProviderState * WIP: calculate attestation state * WIP: calculate attestation state 2 * formatting * Comments and moving code around * Fix init in tests * Fix state calculation flow * Cleanup state calculation and fix tests. * Cleanup and fixes. * Comments * formatting * Fix import * Typo fixes and additional comments * FIRAppAttestInitialHandshakeResponse API * Cleanup state calculation using FBLPromiseAwait * Cleanup * style * FIRAppAttestArtifactStorage implementation and tests (#8041) * Update comments * FIRAppAttestArtifactStorage implementation and tests * Fix init * API docs * Clean up storage in tests * Comments * Disable Keychain dependent tests for SPM * Implement App Attest `getRandomChallenge` (#8033) * Initial implementation * Parse response body for challenge and stub test cases * Review [Draft] * Avoid encoding challenge again * Add tests * Revert "Avoid encoding challenge again" and add TODO This reverts commit 69eb00d. * Document tests; Add test * Tests: Add URL validation check * Review * Define Exchange AppAttest Assertion for FAC token API (#8058) * App Check App Attest: attestation request (#8059) * App Attest provider API integration WIP * update tests * Draft attestation response parsing * Attestation request draft * style * AppAttest Attestation API tests draft * Error cases tests * style * Cleanup and API docs * Merge fix * Fix OCMock imports * Fix nullability modifier * Formatting * comments * App Check App Attest initial handshake adjustments (#8067) * calculatre sha256 of random challenge for attestation * Test app adjustments * cleanup * use trailing closures in the test app * Implement API for ExchangeAppAttestAssertionRequest endpoint (#8065) * Implement assertion exchange * Tweak existing tests * Add tests * Rename JSON to better match gRPC message * Add HTTPBody helper * Review * Review 2 * Review 3 * App Check App Attest assertion flow (#8083) * App Attest assertion workflow draft * send request * assertion flow tests * style * App Check: store App Attest artifact per key ID (#8097) * Update artifact storage API and tests * Artifact storage implementation update * Save artifact for a key ID * Style * typos * App Check: prevent concurrent token requests (#8117) * App Attest multiple get token method invocation tests * Ensure a single App Attest handshake sequence at the time * FIRAppCheckTests: get token request merging tests * FIRAppCheck: Ensure a single get token operation at the time * formatting * Test new request after merged requests * Release finished operation promise * Style * Typos * typo * Request merging tests for error cases * formatting * Changelog * App Check App Attest: handle attestation rejection (#8170) * Remove/update outdated TODOs * [WIP] Attestation rejection handling draft * style * retry tests draft * reset key ID before retry * Reset attestation * test error and fixes * style * More details in the name * Some debug logging * style * Use specific codes for log messages * style * Add FIRAppAttestProvider.h the umbrella header Co-authored-by: Nick Cooke <[email protected]>
1 parent e43020e commit 302f91e

File tree

55 files changed

+4208
-103
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+4208
-103
lines changed

FirebaseAppCheck/Apps/FIRAppCheckTestApp/FIRAppCheckTestApp/AppDelegate.swift

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
2626
.LaunchOptionsKey: Any]?) -> Bool {
2727
FirebaseApp.configure()
2828

29-
guard let firebaseApp = FirebaseApp.app() else {
30-
return true
31-
}
32-
33-
FIRDeviceCheckProvider(app: firebaseApp)?.getToken(completion: { token, error in
34-
if let token = token {
35-
print("DeviceCheck token: \(token.token), expiration date: \(token.expirationDate)")
36-
}
37-
38-
if let error = error {
39-
print("DeviceCheck error: \((error as NSError).userInfo)")
40-
}
41-
})
42-
43-
if let debugProvider = FIRAppCheckDebugProvider(app: firebaseApp) {
44-
print("Debug token: \(debugProvider.currentDebugToken())")
29+
requestDeviceCheckToken()
4530

46-
debugProvider.getToken(completion: { token, error in
47-
if let token = token {
48-
print("Debug FAC token: \(token.token), expiration date: \(token.expirationDate)")
49-
}
31+
requestDebugToken()
5032

51-
if let error = error {
52-
print("Debug error: \(error)")
53-
}
54-
})
33+
if #available(iOS 14.0, *) {
34+
requestAppAttestToken()
5535
}
5636

5737
return true
@@ -76,4 +56,64 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
7656
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
7757
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
7858
}
59+
60+
// MARK: App Check providers
61+
62+
func requestDeviceCheckToken() {
63+
guard let firebaseApp = FirebaseApp.app() else {
64+
return
65+
}
66+
67+
DeviceCheckProvider(app: firebaseApp)?.getToken { token, error in
68+
if let token = token {
69+
print("DeviceCheck token: \(token.token), expiration date: \(token.expirationDate)")
70+
}
71+
72+
if let error = error {
73+
print("DeviceCheck error: \((error as NSError).userInfo)")
74+
}
75+
}
76+
}
77+
78+
func requestDebugToken() {
79+
guard let firebaseApp = FirebaseApp.app() else {
80+
return
81+
}
82+
83+
if let debugProvider = AppCheckDebugProvider(app: firebaseApp) {
84+
print("Debug token: \(debugProvider.currentDebugToken())")
85+
86+
debugProvider.getToken { token, error in
87+
if let token = token {
88+
print("Debug FAC token: \(token.token), expiration date: \(token.expirationDate)")
89+
}
90+
91+
if let error = error {
92+
print("Debug error: \(error)")
93+
}
94+
}
95+
}
96+
}
97+
98+
@available(iOS 14.0, *)
99+
func requestAppAttestToken() {
100+
guard let firebaseApp = FirebaseApp.app() else {
101+
return
102+
}
103+
104+
guard let appAttestProvider = AppAttestProvider(app: firebaseApp) else {
105+
print("Failed to instantiate AppAttestProvider")
106+
return
107+
}
108+
109+
appAttestProvider.getToken { token, error in
110+
if let token = token {
111+
print("App Attest FAC token: \(token.token), expiration date: \(token.expirationDate)")
112+
}
113+
114+
if let error = error {
115+
print("App Attest error: \(error)")
116+
}
117+
}
118+
}
79119
}

FirebaseAppCheck/Apps/FIRAppCheckTestApp/Podfile

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,5 @@ target 'FIRAppCheckTestApp' do
1111
pod 'FirebaseAppCheck', :path => '../../../'
1212

1313
pod 'FirebaseCore', :path => '../../../'
14-
pod 'GoogleUtilities', :path => '../../../'
1514
pod 'FirebaseCoreDiagnostics', :path => '../../../'
16-
pod 'GoogleDataTransport', :path => '../../../'
1715
end

FirebaseAppCheck/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
# 8.1.0 -- M97
2+
- [added] Apple's App Attest attestation provider support. (#8133)
13
# v8.0.0 -- M95
24
- [added] Firebase abuse reduction support SDK. (#7928, #7937, #7948)
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2021 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import <Foundation/Foundation.h>
18+
19+
@class FBLPromise<Result>;
20+
@class FIRAppAttestAttestationResponse;
21+
@class FIRAppCheckToken;
22+
@protocol FIRAppCheckAPIServiceProtocol;
23+
24+
NS_ASSUME_NONNULL_BEGIN
25+
26+
/// Methods to send API requests required for App Attest based attestation sequence.
27+
@protocol FIRAppAttestAPIServiceProtocol <NSObject>
28+
29+
/// Request a random challenge from server.
30+
- (FBLPromise<NSData *> *)getRandomChallenge;
31+
32+
/// Sends attestation data to Firebase backend for validation.
33+
/// @param attestation The App Attest key attestation data obtained from the method
34+
/// `-[DCAppAttestService attestKey:clientDataHash:completionHandler:]` using the random challenge
35+
/// received from Firebase backend.
36+
/// @param keyID The key ID used to generate the attestation.
37+
/// @param challenge The challenge used to generate the attestation.
38+
/// @return A promise that is fulfilled with a response object with an encrypted attestation
39+
/// artifact and an Firebase App Check token or rejected with an error.
40+
- (FBLPromise<FIRAppAttestAttestationResponse *> *)attestKeyWithAttestation:(NSData *)attestation
41+
keyID:(NSString *)keyID
42+
challenge:(NSData *)challenge;
43+
44+
/// Exchanges attestation data (artifact & assertion) and a challenge for a FAC token.
45+
- (FBLPromise<FIRAppCheckToken *> *)getAppCheckTokenWithArtifact:(NSData *)artifact
46+
challenge:(NSData *)challenge
47+
assertion:(NSData *)assertion;
48+
49+
@end
50+
51+
/// A default implementation of `FIRAppAttestAPIServiceProtocol`.
52+
@interface FIRAppAttestAPIService : NSObject <FIRAppAttestAPIServiceProtocol>
53+
54+
/// Default initializer.
55+
/// @param APIService An instance implementing `FIRAppCheckAPIServiceProtocol` to be used to send
56+
/// network requests to Firebase App Check backend.
57+
/// @param projectID A Firebase project ID for the requests (`FIRApp.options.projectID`).
58+
/// @param appID A Firebase app ID for the requests (`FIRApp.options.googleAppID`).
59+
- (instancetype)initWithAPIService:(id<FIRAppCheckAPIServiceProtocol>)APIService
60+
projectID:(NSString *)projectID
61+
appID:(NSString *)appID;
62+
63+
@end
64+
65+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)