FIRInstanceIDKeyPairMigrationTest.m 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright 2019 Google
  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. #import <XCTest/XCTest.h>
  17. #import "Firebase/InstanceID/FIRInstanceIDBackupExcludedPlist.h"
  18. #import "Firebase/InstanceID/FIRInstanceIDConstants.h"
  19. #import "Firebase/InstanceID/FIRInstanceIDKeyPair.h"
  20. #import "Firebase/InstanceID/FIRInstanceIDKeychain.h"
  21. #import <OCMock/OCMock.h>
  22. #import "Firebase/InstanceID/FIRInstanceIDKeyPair.h"
  23. #import "Firebase/InstanceID/FIRInstanceIDKeyPairStore.h"
  24. #import "Firebase/InstanceID/FIRInstanceIDKeyPairUtilities.h"
  25. #import "Firebase/InstanceID/FIRInstanceIDUtilities.h"
  26. @interface FIRInstanceIDKeyPairStore (ExposedForTest)
  27. @property(nonatomic, readwrite, strong) FIRInstanceIDBackupExcludedPlist *plist;
  28. @property(atomic, readwrite, strong) FIRInstanceIDKeyPair *keyPair;
  29. BOOL FIRInstanceIDHasMigratedKeyPair(NSString *legacyPublicKeyTag, NSString *newPublicKeyTag);
  30. NSString *FIRInstanceIDLegacyPublicTagWithSubtype(NSString *subtype);
  31. NSString *FIRInstanceIDLegacyPrivateTagWithSubtype(NSString *subtype);
  32. NSString *FIRInstanceIDPublicTagWithSubtype(NSString *subtype);
  33. NSString *FIRInstanceIDPrivateTagWithSubtype(NSString *subtype);
  34. + (FIRInstanceIDKeyPair *)keyPairForPrivateKeyTag:(NSString *)privateKeyTag
  35. publicKeyTag:(NSString *)publicKeyTag
  36. error:(NSError *__autoreleasing *)error;
  37. + (void)deleteKeyPairWithPrivateTag:(NSString *)privateTag
  38. publicTag:(NSString *)publicTag
  39. handler:(void (^)(NSError *))handler;
  40. - (void)migrateKeyPairCacheIfNeededWithHandler:(void (^)(NSError *error))handler;
  41. + (NSString *)keyStoreFileName;
  42. - (void)updateKeyRef:(SecKeyRef)keyRef
  43. withTag:(NSString *)tag
  44. handler:(void (^)(NSError *error))handler;
  45. @end
  46. // Need to separate the tests from FIRInstanceIDKeyPairStoreTest for separate keychain operations
  47. @interface FIRInstanceIDKeyPairMigrationTest : XCTestCase
  48. @property(nonatomic, readwrite, strong) FIRInstanceIDKeyPairStore *keyPairStore;
  49. @end
  50. @implementation FIRInstanceIDKeyPairMigrationTest
  51. - (void)setUp {
  52. [super setUp];
  53. id mockStoreClass = OCMClassMock([FIRInstanceIDKeyPairStore class]);
  54. [[[mockStoreClass stub] andReturn:@"com.google.iid-keypairmanager-test"] keyStoreFileName];
  55. _keyPairStore = [[FIRInstanceIDKeyPairStore alloc] init];
  56. }
  57. - (void)tearDown {
  58. [super tearDown];
  59. NSError *error = nil;
  60. [self.keyPairStore removeKeyPairCreationTimePlistWithError:&error];
  61. // TODO: Real FIRInstanceIDKeychain should not be used for the tests, it should be mocked instead.
  62. // Drain Keychain private queue before exiting.
  63. [[FIRInstanceIDKeychain sharedInstance] itemWithQuery:@{}];
  64. }
  65. - (void)testMigrationDataIfLegacyKeyPairsNotExist {
  66. NSString *legacyPublicKeyTag =
  67. FIRInstanceIDLegacyPublicTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  68. NSString *publicKeyTag = FIRInstanceIDPublicTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  69. XCTAssertFalse(FIRInstanceIDHasMigratedKeyPair(legacyPublicKeyTag, publicKeyTag));
  70. NSString *legacyPrivateKeyTag =
  71. FIRInstanceIDLegacyPrivateTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  72. NSError *error;
  73. FIRInstanceIDKeyPair *keyPair =
  74. [FIRInstanceIDKeyPairStore keyPairForPrivateKeyTag:legacyPrivateKeyTag
  75. publicKeyTag:legacyPublicKeyTag
  76. error:&error];
  77. XCTAssertFalse([keyPair isValid]);
  78. }
  79. - (void)testMigrationIfLegacyKeyPairsExist {
  80. XCTestExpectation *migrationCompleteExpectation =
  81. [self expectationWithDescription:@"migration should be done"];
  82. // create legacy key pairs
  83. NSString *legacyPublicKeyTag =
  84. FIRInstanceIDLegacyPublicTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  85. NSString *legacyPrivateKeyTag =
  86. FIRInstanceIDLegacyPrivateTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  87. FIRInstanceIDKeyPair *keyPair =
  88. [[FIRInstanceIDKeychain sharedInstance] generateKeyPairWithPrivateTag:legacyPrivateKeyTag
  89. publicTag:legacyPublicKeyTag];
  90. XCTAssertTrue([keyPair isValid]);
  91. NSError *error;
  92. NSString *publicKeyTag = FIRInstanceIDPublicTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  93. NSString *privateKeyTag = FIRInstanceIDPrivateTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  94. XCTAssertFalse(FIRInstanceIDHasMigratedKeyPair(legacyPublicKeyTag, publicKeyTag));
  95. FIRInstanceIDKeyPair *keyPair1 =
  96. [FIRInstanceIDKeyPairStore keyPairForPrivateKeyTag:legacyPrivateKeyTag
  97. publicKeyTag:legacyPublicKeyTag
  98. error:&error];
  99. XCTAssertTrue([keyPair1 isValid]);
  100. [self.keyPairStore migrateKeyPairCacheIfNeededWithHandler:^(NSError *error) {
  101. XCTAssertNil(error);
  102. XCTAssertTrue(FIRInstanceIDHasMigratedKeyPair(legacyPublicKeyTag, publicKeyTag));
  103. FIRInstanceIDKeyPair *keyPair2 =
  104. [FIRInstanceIDKeyPairStore keyPairForPrivateKeyTag:privateKeyTag
  105. publicKeyTag:publicKeyTag
  106. error:&error];
  107. XCTAssertTrue([keyPair2 isValid]);
  108. XCTAssertEqualObjects(keyPair.publicKeyData, keyPair2.publicKeyData);
  109. XCTAssertEqualObjects(keyPair.privateKeyData, keyPair2.privateKeyData);
  110. // Clear the legacy data after tests
  111. [FIRInstanceIDKeyPairStore deleteKeyPairWithPrivateTag:legacyPrivateKeyTag
  112. publicTag:legacyPublicKeyTag
  113. handler:^(NSError *error) {
  114. XCTAssertNil(error);
  115. [migrationCompleteExpectation fulfill];
  116. }];
  117. }];
  118. [self waitForExpectationsWithTimeout:1 handler:nil];
  119. }
  120. - (void)testUpdateKeyRefWithTagRetainsAndReleasesKeyRef {
  121. __weak id weakKeyRef;
  122. // Use a local autorelease pool to make sure any autorelease objects allocated will be released.
  123. @autoreleasepool {
  124. SecKeyRef keyRef = [self generateKeyRef];
  125. weakKeyRef = (__bridge id)(keyRef);
  126. XCTestExpectation *completionExpectation =
  127. [self expectationWithDescription:@"completionExpectation"];
  128. [self.keyPairStore updateKeyRef:keyRef
  129. withTag:@"test"
  130. handler:^(NSError *error) {
  131. [completionExpectation fulfill];
  132. }];
  133. // Release locally allocated CoreFoundation object.
  134. CFRelease(keyRef);
  135. }
  136. // Should be still alive until execution finished
  137. XCTAssertNotNil(weakKeyRef);
  138. [self waitForExpectationsWithTimeout:0.5 handler:NULL];
  139. // Should be released once finished
  140. // The check below is flaky for build under DEBUG (petentially due to ARC specifics).
  141. // Comment it so far as not-so-important one.
  142. // XCTAssertNil(weakKeyRef);
  143. }
  144. - (SecKeyRef)generateKeyRef {
  145. NSDictionary *keyAttributes = @{(__bridge id)kSecAttrIsPermanent : @YES};
  146. NSDictionary *keyPairAttributes = @{
  147. (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeRSA,
  148. (__bridge id)kSecAttrLabel : @"[FIRInstanceIDKeyPairMigrationTest generateKeyRef]",
  149. (__bridge id)kSecAttrKeySizeInBits : @(2048),
  150. (__bridge id)kSecPrivateKeyAttrs : keyAttributes,
  151. (__bridge id)kSecPublicKeyAttrs : keyAttributes,
  152. };
  153. SecKeyRef publicKey = NULL;
  154. SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttributes, &publicKey, NULL);
  155. return publicKey;
  156. }
  157. @end