2222// THE SOFTWARE.
2323
2424#import < XCTest/XCTest.h>
25- #import < Security/Security.h>
2625#import " MSIDKeychainUtil.h"
2726#import " MSIDWorkPlaceJoinUtil.h"
2827#import " MSIDWorkPlaceJoinConstants.h"
3736
3837@interface MSIDWorkPlaceJoinUtilTests : XCTestCase
3938@property (nonatomic ) MSIDTestSecureEnclaveKeyPairGenerator *eccKeyGenerator;
40- @property (atomic , strong ) NSMutableDictionary *keyGens;
4139@property (nonatomic ) BOOL useIosStyleKeychain;
4240@end
4341
@@ -68,7 +66,6 @@ - (void)setUp {
6866#if TARGET_OS_OSX
6967 self.useIosStyleKeychain = NO ;
7068#endif
71- self.keyGens = [NSMutableDictionary new ];
7269}
7370
7471- (void )tearDown
@@ -78,7 +75,6 @@ - (void)tearDown
7875 [self cleanWPJ: [self keychainGroup: YES ]];
7976 [self cleanWPJ: [self keychainGroup: NO ]];
8077 }
81- self.keyGens = nil ;
8278 [MSIDTestSwizzle reset ];
8379}
8480
@@ -501,186 +497,8 @@ - (void)testGetWPJKeysWithNilTenantId_WithNoSecureEnclave_shouldReturnPrimaryReg
501497 NSString *expectedSubject = [kDummyTenant1CertIdentifier msidBase64UrlDecode ];
502498 XCTAssertEqualObjects (expectedSubject, result.certificateSubject );
503499}
504- /*
505- #pragma mark - Transport Key Tests
506- - (void)testGetWPJKeysWithTenantId_whenEccRegistrationWithTransportKey_shouldReturnBothKeys
507- {
508- [self insertDummyEccRegistrationForTenantIdentifier:@"tenantId" certIdentifier:kDummyTenant1CertIdentifier useSecureEnclave:YES];
509-
510- MSIDWPJKeyPairWithCert *result = [MSIDWorkPlaceJoinUtil getWPJKeysWithTenantId:@"tenantId" context:nil];
511-
512- XCTAssertNotNil(result);
513- XCTAssertEqual(result.keyChainVersion, MSIDWPJKeychainAccessGroupV2);
514- XCTAssertTrue(result.privateKeyRef != NULL);
515- XCTAssertTrue(result.privateTransportKeyRef != NULL);
516- }
517-
518- - (void)testGetWPJKeysWithTenantId_whenEccRegistrationWithoutSecureEnclave_shouldReturnBothKeys
519- {
520- [self insertDummyEccRegistrationForTenantIdentifier:@"tenantId" certIdentifier:kDummyTenant1CertIdentifier useSecureEnclave:NO];
521-
522- MSIDWPJKeyPairWithCert *result = [MSIDWorkPlaceJoinUtil getWPJKeysWithTenantId:@"tenantId" context:nil];
523-
524- XCTAssertNotNil(result);
525- XCTAssertEqual(result.keyChainVersion, MSIDWPJKeychainAccessGroupV2);
526- XCTAssertTrue(result.privateKeyRef != NULL);
527- XCTAssertTrue(result.privateTransportKeyRef != NULL);
528- }
529-
530- - (void)testGetWPJKeysWithTenantId_whenEccRegistrationWithMissingTransportKey_shouldReturnOnlyDeviceKey
531- {
532- NSString *tenantId = @"tenantId-test-abc";
533- // Insert device key and cert but skip transport key
534- SecCertificateRef certRef = [self dummyEccCertRef:kDummyTenant1CertIdentifier];
535- NSString *tag = [NSString stringWithFormat:@"%@#%@%@", kMSIDPrivateKeyIdentifier, tenantId, @"-EC"];
536- SecKeyRef keyRef = [self createAndGetdummyEccPrivateKey:NO privateKeyTag:tag];
537- NSString *keychainGroup = [self keychainGroup:NO];
538-
539- OSStatus status = [self insertDummyDRSIdentityIntoKeychain:certRef
540- privateKeyRef:keyRef
541- privateKeyTag:tag
542- accessGroup:keychainGroup];
543- XCTAssertTrue(status == errSecSuccess || status == errSecDuplicateItem);
544-
545- // Don't insert transport key - simulate missing STK scenario
546-
547- MSIDWPJKeyPairWithCert *result = [MSIDWorkPlaceJoinUtil getWPJKeysWithTenantId:tenantId context:nil];
548-
549- XCTAssertNotNil(result);
550- XCTAssertEqual(result.keyChainVersion, MSIDWPJKeychainAccessGroupV2);
551- XCTAssertTrue(result.privateKeyRef != NULL);
552- XCTAssertTrue(result.privateTransportKeyRef == NULL, @"Expected privateTransportKeyRef to be nil when transport key is missing");
553- }
554-
555- - (void)testGetWPJKeysWithTenantId_whenPrimaryEccRegistrationWithTransportKey_shouldReturnCorrectKeys
556- {
557- [self addPrimaryEccDefaultRegistrationForTenantId:@"primaryTenant"
558- sharedAccessGroup:[self keychainGroup:NO]
559- certIdentifier:kDummyTenant1CertIdentifier
560- useSecureEnclave:YES];
561-
562- MSIDWPJKeyPairWithCert *result = [MSIDWorkPlaceJoinUtil getWPJKeysWithTenantId:nil context:nil];
563-
564- XCTAssertNotNil(result);
565- XCTAssertEqual(result.keyChainVersion, MSIDWPJKeychainAccessGroupV2);
566- XCTAssertTrue(result.privateKeyRef != NULL, @"Primary registration should have device key");
567- XCTAssertTrue(result.privateTransportKeyRef != NULL, @"Primary registration should have transport key");
568- }
569-
570- - (void)testGetWPJKeysWithTenantId_whenLegacyRegistration_shouldHaveNoTransportKey
571- {
572- [self insertDummyWPJInLegacyFormat:YES tenantIdentifier:@"tenantId" writeTenantMetadata:YES certIdentifier:kDummyTenant1CertIdentifier];
573-
574- MSIDWPJKeyPairWithCert *result = [MSIDWorkPlaceJoinUtil getWPJKeysWithTenantId:@"tenantId" context:nil];
575-
576- XCTAssertNotNil(result);
577- XCTAssertEqual(result.keyChainVersion, MSIDWPJKeychainAccessGroupV1);
578- XCTAssertTrue(result.privateKeyRef != NULL, @"Legacy registration should have device key");
579- XCTAssertTrue(result.privateTransportKeyRef == NULL, @"Legacy registration should not have transport key");
580- }
581-
582- - (void)testGetWPJKeysWithTenantId_whenTransportKeyInDifferentAccessGroup_shouldHandleCorrectly
583- {
584- // Insert device key in correct access group
585- SecCertificateRef certRef = [self dummyEccCertRef:kDummyTenant1CertIdentifier];
586- NSString *tag = [NSString stringWithFormat:@"%@#%@%@", kMSIDPrivateKeyIdentifier, @"tenantId", @"-EC"];
587- SecKeyRef keyRef = [self createAndGetdummyEccPrivateKey:NO privateKeyTag:tag];
588- NSString *keychainGroup = [self keychainGroup:NO];
589-
590- OSStatus status = [self insertDummyDRSIdentityIntoKeychain:certRef
591- privateKeyRef:keyRef
592- privateKeyTag:tag
593- accessGroup:keychainGroup];
594- XCTAssertEqual(status, errSecSuccess);
595-
596- // Transport key would be inserted with same access group, so this tests normal flow
597- NSString *stkTag = [NSString stringWithFormat:@"%@#%@%@", kMSIDPrivateTransportKeyIdentifier, @"tenantId", @"-EC"];
598- SecKeyRef transportKeyRef = [self createAndGetdummyEccPrivateKey:NO privateKeyTag:stkTag];
599-
600- [self insertKeyIntoKeychain:transportKeyRef privateKeyTag:stkTag accessGroup:keychainGroup];
601-
602- MSIDWPJKeyPairWithCert *result = [MSIDWorkPlaceJoinUtil getWPJKeysWithTenantId:@"tenantId" context:nil];
603-
604- XCTAssertNotNil(result);
605- XCTAssertTrue(result.privateKeyRef != NULL);
606- XCTAssertTrue(result.privateTransportKeyRef != NULL);
607- }
608-
609- - (void)testGetWPJKeysWithTenantId_whenRSARegistrationInV2Format_shouldNotHaveTransportKey
610- {
611- // For iOS, RSA keys in V2 format should not have transport keys
612- // This tests the case where we have RSA device key but no transport key expected
613-
614- [self insertDummyWPJInLegacyFormat:NO tenantIdentifier:@"tenantId" writeTenantMetadata:YES certIdentifier:kDummyTenant1CertIdentifier];
615-
616- MSIDWPJKeyPairWithCert *result = [MSIDWorkPlaceJoinUtil getWPJKeysWithTenantId:@"tenantId" context:nil];
617-
618- // For RSA registrations, transport key should be nil even in V2 format
619- XCTAssertNotNil(result);
620- XCTAssertEqual(result.keyChainVersion, MSIDWPJKeychainAccessGroupV2);
621- XCTAssertTrue(result.privateKeyRef != NULL, @"Expected privateKeyRef to be non-nil for RSA registration in V2 format");
622- XCTAssertTrue(result.privateTransportKeyRef == NULL, @"Expected privateTransportKeyRef to be nil for RSA registration in V2 format");
623- }
624-
625- #pragma mark - Transport Key Edge Cases
626-
627- - (void)testGetWPJKeysWithTenantId_whenKeychainReturnsUnexpectedData_shouldHandleGracefully
628- {
629- // Insert normal device key
630- SecCertificateRef certRef = [self dummyEccCertRef:kDummyTenant1CertIdentifier];
631- NSString *tag = [NSString stringWithFormat:@"%@#%@%@", kMSIDPrivateKeyIdentifier, @"tenantId", @"-EC"];
632- SecKeyRef keyRef = [self createAndGetdummyEccPrivateKey:NO privateKeyTag:tag];
633- NSString *keychainGroup = [self keychainGroup:NO];
634-
635- OSStatus status = [self insertDummyDRSIdentityIntoKeychain:certRef
636- privateKeyRef:keyRef
637- privateKeyTag:tag
638- accessGroup:keychainGroup];
639-
640- MSIDWPJKeyPairWithCert *result = [MSIDWorkPlaceJoinUtil getWPJKeysWithTenantId:@"tenantId" context:nil];
641-
642- // Should return device key even if transport key lookup fails
643- XCTAssertNotNil(result);
644- XCTAssertTrue(result.privateKeyRef != NULL, @"Device key should be present");
645- // Transport key might be nil if lookup fails, which is acceptable
646-
647- }
648-
649- - (void)testGetWPJKeysWithTenantId_concurrentAccess_shouldBeThreadSafe
650- {
651- [self insertDummyEccRegistrationForTenantIdentifier:@"tenantId" certIdentifier:kDummyTenant1CertIdentifier useSecureEnclave:YES];
652-
653- dispatch_group_t group = dispatch_group_create();
654- __block NSMutableArray *results = [NSMutableArray array];
655- __block NSLock *lock = [[NSLock alloc] init];
656-
657- // Launch multiple concurrent requests
658- for (int i = 0; i < 5; i++) {
659- dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
660- MSIDWPJKeyPairWithCert *result = [MSIDWorkPlaceJoinUtil getWPJKeysWithTenantId:@"tenantId" context:nil];
661-
662- [lock lock];
663- if (result) {
664- [results addObject:result];
665- }
666- [lock unlock];
667- });
668- }
669-
670- // Wait for all requests to complete
671- dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
672-
673- // All requests should succeed
674- XCTAssertTrue(results.count == 5, @"All concurrent requests should succeed");
675-
676- // Verify all results have transport keys
677- for (MSIDWPJKeyPairWithCert *result in results) {
678- XCTAssertTrue(result.privateKeyRef != NULL);
679- XCTAssertTrue(result.privateTransportKeyRef != NULL);
680- }
681-
682- }*/
683500#endif
501+
684502#pragma mark - Helpers
685503
686504- (void )cleanWPJ : (NSString *)keychainGroup
@@ -742,29 +560,18 @@ - (OSStatus)insertDummyEccRegistrationForTenantIdentifier:(NSString *)tenantIden
742560 certIdentifier : (NSString *)certIdentifier
743561 useSecureEnclave : (BOOL )useEncSecureEnclave
744562{
745- @synchronized (self) {
746- SecCertificateRef certRef = [self dummyEccCertRef: certIdentifier];
747- XCTAssertTrue (certRef != NULL );
748- // Append Suffix kMSIDPrivateKeyIdentifier
749- NSString *tag = [NSString stringWithFormat: @" %@ #%@%@ " , kMSIDPrivateKeyIdentifier , tenantIdentifier, @" -EC" ];
750- SecKeyRef keyRef = [self createAndGetdummyEccPrivateKey: useEncSecureEnclave privateKeyTag: tag];
751- XCTAssertTrue (keyRef != NULL );
752- NSString *keychainGroup = [self keychainGroup: NO ];
753- OSStatus status = [self insertDummyDRSIdentityIntoKeychain: certRef
754- privateKeyRef: keyRef
755- privateKeyTag: tag
756- accessGroup: keychainGroup];
757- #if TARGET_OS_IOS
758- // If on iOS, insert dummy key to represent STK. STK is required by 1P apps for decrypting bound refresh tokens.
759- NSString *stkTag = [NSString stringWithFormat: @" %@ #%@%@ " , kMSIDPrivateTransportKeyIdentifier , tenantIdentifier, @" -EC" ];
760- SecKeyRef transportKeyRef = [self createAndGetdummyEccPrivateKey: useEncSecureEnclave privateKeyTag: stkTag];
761- XCTAssertTrue (transportKeyRef != NULL );
762- [self insertKeyIntoKeychain: transportKeyRef
763- privateKeyTag: stkTag
764- accessGroup: keychainGroup];
765- #endif
766- return status;
767- }
563+ SecCertificateRef certRef = [self dummyEccCertRef: certIdentifier];
564+ XCTAssertTrue (certRef != NULL );
565+ // Append Suffix kMSIDPrivateKeyIdentifier
566+ NSString *tag = [NSString stringWithFormat: @" %@ #%@%@ " , kMSIDPrivateKeyIdentifier , tenantIdentifier, @" -EC" ];
567+ SecKeyRef keyRef = [self createAndGetdummyEccPrivateKey: useEncSecureEnclave privateKeyTag: tag];
568+ XCTAssertTrue (keyRef != NULL );
569+ NSString *keychainGroup = [self keychainGroup: NO ];
570+ OSStatus status = [self insertDummyDRSIdentityIntoKeychain: certRef
571+ privateKeyRef: keyRef
572+ privateKeyTag: tag
573+ accessGroup: keychainGroup];
574+ return status;
768575}
769576
770577- (OSStatus)insertDummyDRSIdentityIntoKeychain : (SecCertificateRef)certRef
@@ -867,16 +674,12 @@ - (SecKeyRef)dummyPrivateKeyForCertRef
867674
868675- (SecKeyRef)createAndGetdummyEccPrivateKey : (BOOL )useSecureEnclave privateKeyTag : (NSString *)privateKeyTag
869676{
870- MSIDTestSecureEnclaveKeyPairGenerator *keygen = [self .keyGens objectForKey: privateKeyTag];
871- if (!keygen)
872- {
873- self.keyGens [privateKeyTag] = [[MSIDTestSecureEnclaveKeyPairGenerator alloc ]
874- initWithSharedAccessGroup: [self keychainGroup: NO ]
875- useSecureEnclave: useSecureEnclave
876- applicationTag: privateKeyTag];
877- keygen = self.keyGens [privateKeyTag];
878- }
879- return keygen.eccPrivateKey ;
677+ self.eccKeyGenerator = [[MSIDTestSecureEnclaveKeyPairGenerator alloc ]
678+ initWithSharedAccessGroup: [self keychainGroup: NO ]
679+ useSecureEnclave: useSecureEnclave
680+ applicationTag: privateKeyTag];
681+ XCTAssertNotNil (self.eccKeyGenerator );
682+ return self.eccKeyGenerator .eccPrivateKey ;
880683}
881684
882685- (NSString *)keychainGroup : (BOOL )useLegacyFormat
0 commit comments