Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(AWSIoT): Fixing crash in AWSIoTMQTTClient #5185

Merged
merged 18 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions AWSIoT/AWSIoTDataManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ - (instancetype)init {
return nil;
}

- (void)dealloc
{
[self.timer invalidate];
}

- (instancetype)initWithName:(NSString *)name
debug:(BOOL)enableDebugging
versioned:(BOOL)enableVersioning
Expand Down
101 changes: 56 additions & 45 deletions AWSIoT/AWSIoTManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -206,19 +206,29 @@ - (void)createKeysAndCertificateFromCsr:(NSDictionary<NSString *, NSString*> *)c

SecKeyRef publicKeyRef = [AWSIoTKeychain getPublicKeyRef:publicTag];
SecKeyRef privateKeyRef = [AWSIoTKeychain getPrivateKeyRef:privateTag];
SecIdentityRef identityRef = [AWSIoTKeychain getIdentityRef:newPrivateTag certificateLabel:newCertTag];

if ([AWSIoTKeychain deleteAsymmetricKeysWithPublicTag:publicTag privateTag:privateTag] &&
[AWSIoTKeychain addPrivateKeyRef:privateKeyRef tag:newPrivateTag] &&
[AWSIoTKeychain addPublicKeyRef:publicKeyRef tag:newPublicTag] &&
[AWSIoTKeychain addCertificateToKeychain:certificatePem tag:newCertTag] &&
[AWSIoTKeychain getIdentityRef:newPrivateTag certificateLabel:newCertTag] != nil) {
identityRef != nil) {
AWSIoTCreateCertificateResponse* resp = [[AWSIoTCreateCertificateResponse alloc] init];
resp.certificateId = certificateId;
resp.certificatePem = certificatePem;
resp.certificateArn = certificateArn;

validatedResponse = resp;
}
if (identityRef) {
CFRelease(identityRef);
}
if (privateKeyRef) {
CFRelease(privateKeyRef);
}
if (publicKeyRef) {
CFRelease(publicKeyRef);
}
}
}

Expand All @@ -229,13 +239,11 @@ - (void)createKeysAndCertificateFromCsr:(NSDictionary<NSString *, NSString*> *)c
}

+ (BOOL)importIdentityFromPKCS12Data:(NSData *)pkcs12Data passPhrase:(NSString *)passPhrase certificateId:(NSString *)certificateId {
SecKeyRef privateKey = NULL;
SecKeyRef publicKey = NULL;
SecCertificateRef certRef = NULL;

[AWSIoTManager readPk12:pkcs12Data passPhrase:passPhrase certRef:&certRef privateKeyRef:&privateKey publicKeyRef:&publicKey];
__block SecKeyRef privateKey = NULL;
__block SecKeyRef publicKey = NULL;
__block SecCertificateRef certRef = NULL;

if (!certRef || !privateKey || !publicKey) {
void (^cleanup)(void) = ^void {
if (certRef) {
CFRelease(certRef);
}
Expand All @@ -245,6 +253,12 @@ + (BOOL)importIdentityFromPKCS12Data:(NSData *)pkcs12Data passPhrase:(NSString *
if (publicKey) {
CFRelease(publicKey);
}
};

[AWSIoTManager readPk12:pkcs12Data passPhrase:passPhrase certRef:&certRef privateKeyRef:&privateKey publicKeyRef:&publicKey];

if (!certRef || !privateKey || !publicKey) {
cleanup();
AWSDDLogError(@"Unable to extract PKCS12 data. Ensure the passPhrase is correct.");
return NO;
}
Expand All @@ -254,27 +268,26 @@ + (BOOL)importIdentityFromPKCS12Data:(NSData *)pkcs12Data passPhrase:(NSString *
NSString *certTag = [AWSIoTManager certTagWithCertificateId:certificateId];

if (![AWSIoTKeychain addPrivateKeyRef:privateKey tag:privateTag]) {
if (publicKey) {
CFRelease(publicKey);
}
cleanup();
AWSDDLogError(@"Unable to add private key");
return NO;
}

if (![AWSIoTKeychain addPublicKeyRef:publicKey tag:publicTag]) {
[AWSIoTKeychain deleteAsymmetricKeysWithPublicTag:publicTag privateTag:privateTag];

cleanup();
AWSDDLogError(@"Unable to add public key");
return NO;
}

if (![AWSIoTKeychain addCertificateRef:certRef tag:certTag]) {
[AWSIoTKeychain deleteAsymmetricKeysWithPublicTag:publicTag privateTag:privateTag];

cleanup();
AWSDDLogError(@"Unable to add certificate");
return NO;
}

cleanup();
return YES;
}

Expand All @@ -283,40 +296,38 @@ + (BOOL)importIdentityFromPKCS12Data:(NSData *)pkcs12Data passPhrase:(NSString *
//
+ (BOOL)readPk12:(NSData *)pk12Data passPhrase:(NSString *)passPhrase certRef:(SecCertificateRef *)certRef privateKeyRef:(SecKeyRef *)privateKeyRef publicKeyRef:(SecKeyRef *)publicKeyRef
{
SecPolicyRef policy = NULL;
SecTrustRef trust = NULL;

__block SecPolicyRef policy = NULL;
__block SecTrustRef trust = NULL;
__block CFArrayRef secImportItems = NULL;

// cleanup stuff in a block so we don't need to do this over and over again.
static BOOL (^cleanup)(void);
static BOOL (^errorCleanup)(void);
static dispatch_once_t once;
dispatch_once(&once, ^{
cleanup = ^BOOL {
if(policy) {
CFRelease(policy);
}

if(trust) {
CFRelease(trust);
}

return YES;
};

errorCleanup = ^BOOL {
*privateKeyRef = NULL;
*publicKeyRef = NULL;
*certRef = NULL;

cleanup();

return NO;
};
});

BOOL (^cleanup)(void) = ^BOOL {
if (secImportItems) {
CFRelease(secImportItems);
}

if (policy) {
CFRelease(policy);
}

if (trust) {
CFRelease(trust);
}

return YES;
};

BOOL (^errorCleanup)(void) = ^BOOL {
*privateKeyRef = NULL;
*publicKeyRef = NULL;
*certRef = NULL;

cleanup();

return NO;
};

CFDictionaryRef secImportOptions = (__bridge CFDictionaryRef) @{(__bridge id) kSecImportExportPassphrase : passPhrase};
CFArrayRef secImportItems = NULL;

OSStatus status = SecPKCS12Import((__bridge CFDataRef) pk12Data, (CFDictionaryRef) secImportOptions, &secImportItems);

if (status == errSecSuccess && CFArrayGetCount(secImportItems) > 0)
Expand Down Expand Up @@ -369,7 +380,7 @@ + (BOOL)readPk12:(NSData *)pk12Data passPhrase:(NSString *)passPhrase certRef:(S
AWSDDLogError(@"Unable to copy public key");
return errorCleanup();
}

return cleanup();
}
AWSDDLogError(@"Unable to import from PKCS12 data");
Expand Down
11 changes: 8 additions & 3 deletions AWSIoT/Internal/AWSIoTCSR.m
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,12 @@ - (NSData*)generateCSRForCertificate:(NSString*)certificateId {
NSString *privateTag = [AWSIoTKeychain.privateKeyTag stringByAppendingString:certificateId];

_publicKeyBits = [AWSIoTKeychain getPublicKeyBits:publicTag];
SecKeyRef privateKeyRef = [AWSIoTKeychain getPrivateKeyRef:privateTag];
if (!_publicKeyBits) {
return nil;
}

if (!_publicKeyBits || !privateKeyRef) {
SecKeyRef privateKeyRef = [AWSIoTKeychain getPrivateKeyRef:privateTag];
if (!privateKeyRef) {
return nil;
}

Expand Down Expand Up @@ -113,7 +116,9 @@ - (NSData*)generateCSRForCertificate:(NSString*)certificateId {
[scr appendData:signdata];

[self addByte:seqTag intoData:scr];


CFRelease(privateKeyRef);
ruisebas marked this conversation as resolved.
Show resolved Hide resolved

return [scr copy];
}

Expand Down
20 changes: 10 additions & 10 deletions AWSIoT/Internal/AWSIoTKeychain.m
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,13 @@ + (BOOL)isValidCertificate:(NSString*)privateKeyTag certificateLabel:(NSString*)
if (identityRef) {
SecCertificateRef cert = NULL;
OSStatus status = SecIdentityCopyCertificate(identityRef, &cert);
CFRelease(identityRef);
if (status == noErr) {
return YES;
} else {
AWSDDLogError(@"SecIdentityCopyCertificate failed [%d]", (int)status);
}
}

return NO;
}

Expand Down Expand Up @@ -205,7 +205,10 @@ + (BOOL)addCertificate:(NSData*)cert withTag:(NSString*)tag {
AWSDDLogError(@"Error create Sec Certificate from data");
return NO;
}
return [AWSIoTKeychain addCertificateRef:certRef tag:tag];

BOOL result = [AWSIoTKeychain addCertificateRef:certRef tag:tag];
CFRelease(certRef);
return result;
}

+ (BOOL)addCertificateRef:(SecCertificateRef)certRef {
Expand Down Expand Up @@ -305,7 +308,7 @@ + (NSData *)getPublicKeyBits:(NSString*)tag {
publicKeyRef = NULL;
}

return (__bridge NSData *)publicKeyRef;
return (__bridge_transfer NSData *)publicKeyRef;
}

+ (SecKeyRef)getPrivateKeyRef:(NSString*)tag {
Expand Down Expand Up @@ -347,7 +350,7 @@ + (NSData *)getPrivateKeyBits:(NSString*)tag {
privateKeyBits = NULL;
}

return (__bridge NSData *)privateKeyBits;
return (__bridge_transfer NSData *)privateKeyBits;
}

+ (SecIdentityRef)getIdentityRef:(NSString*)privateKeyTag certificateLabel:(NSString *)certificateLabel {
Expand All @@ -374,8 +377,7 @@ + (SecIdentityRef)getIdentityRef:(NSString*)privateKeyTag certificateLabel:(NSSt
+ (BOOL)addPublicKeyRef:(SecKeyRef)pubkeyRef tag:(NSString*)tag {

OSStatus sanityCheck = noErr;
CFTypeRef persistPeer = NULL;


NSMutableDictionary * publicKeyAttr = [[NSMutableDictionary alloc] init];

[publicKeyAttr setObject:(id)kSecClassKey forKey:(id)kSecClass];
Expand All @@ -386,7 +388,7 @@ + (BOOL)addPublicKeyRef:(SecKeyRef)pubkeyRef tag:(NSString*)tag {
[publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnPersistentRef];
[publicKeyAttr setObject:(__bridge id)[AWSIoTKeychain accessibilityType] forKey:(id)kSecAttrAccessible];

sanityCheck = SecItemAdd((CFDictionaryRef) publicKeyAttr, (CFTypeRef *)&persistPeer);
sanityCheck = SecItemAdd((CFDictionaryRef) publicKeyAttr, nil);
if ((sanityCheck != noErr) && (sanityCheck != errSecDuplicateItem)){
AWSDDLogError(@"addPublicKeyRef error: %d",(int)sanityCheck);
return NO;
Expand Down Expand Up @@ -422,8 +424,6 @@ + (BOOL)addPublicKey:(NSData*)pubkey tag:(NSString*)tag {
+ (BOOL)addPrivateKeyRef:(SecKeyRef)privkeyRef tag:(NSString*)tag {

OSStatus sanityCheck = noErr;
CFTypeRef persistPeer = NULL;

NSMutableDictionary * privateKeyAttr = [[NSMutableDictionary alloc] init];

[privateKeyAttr setObject:(id)kSecClassKey forKey:(id)kSecClass];
Expand All @@ -434,7 +434,7 @@ + (BOOL)addPrivateKeyRef:(SecKeyRef)privkeyRef tag:(NSString*)tag {
[privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnPersistentRef];
[privateKeyAttr setObject:(__bridge id)[AWSIoTKeychain accessibilityType] forKey:(id)kSecAttrAccessible];

sanityCheck = SecItemAdd((CFDictionaryRef) privateKeyAttr, (CFTypeRef *)&persistPeer);
sanityCheck = SecItemAdd((CFDictionaryRef) privateKeyAttr, nil);
if ((sanityCheck != noErr) && (sanityCheck != errSecDuplicateItem)){
AWSDDLogError(@"addPrivateKeyRef error: %d",(int)sanityCheck);
return NO;
Expand Down
Loading
Loading