FIRInstanceIDKeyPairMigrationTest.m 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. }
  62. - (void)testMigrationDataIfLegacyKeyPairsNotExist {
  63. NSString *legacyPublicKeyTag =
  64. FIRInstanceIDLegacyPublicTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  65. NSString *publicKeyTag = FIRInstanceIDPublicTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  66. XCTAssertFalse(FIRInstanceIDHasMigratedKeyPair(legacyPublicKeyTag, publicKeyTag));
  67. NSString *legacyPrivateKeyTag =
  68. FIRInstanceIDLegacyPrivateTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  69. NSError *error;
  70. FIRInstanceIDKeyPair *keyPair =
  71. [FIRInstanceIDKeyPairStore keyPairForPrivateKeyTag:legacyPrivateKeyTag
  72. publicKeyTag:legacyPublicKeyTag
  73. error:&error];
  74. XCTAssertFalse([keyPair isValid]);
  75. }
  76. - (void)testMigrationIfLegacyKeyPairsExist {
  77. XCTestExpectation *migrationCompleteExpectation =
  78. [self expectationWithDescription:@"migration should be done"];
  79. // create legacy key pairs
  80. NSString *legacyPublicKeyTag =
  81. FIRInstanceIDLegacyPublicTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  82. NSString *legacyPrivateKeyTag =
  83. FIRInstanceIDLegacyPrivateTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  84. FIRInstanceIDKeyPair *keyPair =
  85. [[FIRInstanceIDKeychain sharedInstance] generateKeyPairWithPrivateTag:legacyPrivateKeyTag
  86. publicTag:legacyPublicKeyTag];
  87. XCTAssertTrue([keyPair isValid]);
  88. NSError *error;
  89. NSString *publicKeyTag = FIRInstanceIDPublicTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  90. NSString *privateKeyTag = FIRInstanceIDPrivateTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  91. XCTAssertFalse(FIRInstanceIDHasMigratedKeyPair(legacyPublicKeyTag, publicKeyTag));
  92. FIRInstanceIDKeyPair *keyPair1 =
  93. [FIRInstanceIDKeyPairStore keyPairForPrivateKeyTag:legacyPrivateKeyTag
  94. publicKeyTag:legacyPublicKeyTag
  95. error:&error];
  96. XCTAssertTrue([keyPair1 isValid]);
  97. [self.keyPairStore migrateKeyPairCacheIfNeededWithHandler:^(NSError *error) {
  98. XCTAssertNil(error);
  99. XCTAssertTrue(FIRInstanceIDHasMigratedKeyPair(legacyPublicKeyTag, publicKeyTag));
  100. FIRInstanceIDKeyPair *keyPair2 =
  101. [FIRInstanceIDKeyPairStore keyPairForPrivateKeyTag:privateKeyTag
  102. publicKeyTag:publicKeyTag
  103. error:&error];
  104. XCTAssertTrue([keyPair2 isValid]);
  105. XCTAssertEqualObjects(keyPair.publicKeyData, keyPair2.publicKeyData);
  106. XCTAssertEqualObjects(keyPair.privateKeyData, keyPair2.privateKeyData);
  107. // Clear the legacy data after tests
  108. [FIRInstanceIDKeyPairStore deleteKeyPairWithPrivateTag:legacyPrivateKeyTag
  109. publicTag:legacyPublicKeyTag
  110. handler:^(NSError *error) {
  111. XCTAssertNil(error);
  112. [migrationCompleteExpectation fulfill];
  113. }];
  114. }];
  115. [self waitForExpectationsWithTimeout:1 handler:nil];
  116. }
  117. - (void)testUpdateKeyRefWithTagRetainsAndReleasesKeyRef {
  118. SecKeyRef publicKeyRef;
  119. @autoreleasepool {
  120. NSString *legacyPublicKeyTag =
  121. FIRInstanceIDLegacyPublicTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  122. NSString *legacyPrivateKeyTag =
  123. FIRInstanceIDLegacyPrivateTagWithSubtype(kFIRInstanceIDKeyPairSubType);
  124. FIRInstanceIDKeyPair *keyPair =
  125. [[FIRInstanceIDKeychain sharedInstance] generateKeyPairWithPrivateTag:legacyPrivateKeyTag
  126. publicTag:legacyPublicKeyTag];
  127. XCTAssertTrue([keyPair isValid]);
  128. publicKeyRef = keyPair.publicKey;
  129. // Retain to keep publicKeyRef alive to verify its reatin count
  130. CFRetain(publicKeyRef);
  131. // 2 = 1 from keyPair + 1 from CFRetain()
  132. XCTAssertEqual(CFGetRetainCount(publicKeyRef), 2);
  133. XCTestExpectation *completionExpectaion =
  134. [self expectationWithDescription:@"completionExpectaion"];
  135. [self.keyPairStore updateKeyRef:keyPair.publicKey
  136. withTag:@"test"
  137. handler:^(NSError *error) {
  138. [completionExpectaion fulfill];
  139. }];
  140. // 3 = from keyPair + 1 from CFRetain() + 1 retained by `updateKeyRef`
  141. XCTAssertEqual(CFGetRetainCount(publicKeyRef), 3);
  142. }
  143. // 2 = 1 from CFRetain() + 1 retained by `updateKeyRef`
  144. XCTAssertEqual(CFGetRetainCount(publicKeyRef), 2);
  145. [self waitForExpectationsWithTimeout:0.5 handler:NULL];
  146. // No one else owns publicKeyRef except the test
  147. XCTAssertEqual(CFGetRetainCount(publicKeyRef), 1);
  148. }
  149. @end