From 728420b5d131b2b6089a0b535f147ef05756b65c Mon Sep 17 00:00:00 2001 From: Dmitry Lobanov Date: Tue, 8 Jun 2021 22:23:32 +0300 Subject: [PATCH 1/4] sources: algorithms crypto security remove key by tag error handling has been improved. By Valeriy Van. --- .../RSFamily/RSKeys/JWTCryptoSecurity.m | 20 +++++++++++++++---- Sources/JWT/Supplement/JWTErrorDescription.m | 14 +++++++------ Sources/JWT/include/JWT/JWTCryptoSecurity.h | 2 +- Sources/JWT/include/JWT/JWTErrorDescription.h | 3 ++- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m b/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m index 8416893a..eeae2357 100644 --- a/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m +++ b/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m @@ -8,6 +8,8 @@ #import #import +#import + @interface JWTMemoryLayout : NSObject + (NSString *)typeUInt8; + (NSString *)typeCUnsignedChar; @@ -129,18 +131,28 @@ + (SecKeyRef)keyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error; { return NULL; } -+ (void)removeKeyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error; { ++ (BOOL)removeKeyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error; { NSData *tagData = [tag dataUsingEncoding:NSUTF8StringEncoding]; if (tagData == nil) { // tell that nothing to remove. - return; + if (error) { + *error = [JWTErrorDescription errorWithCode:JWTUnexpectedError]; + } + return NO; } NSDictionary *removeAttributes = @{ (__bridge NSString*)kSecClass: (__bridge NSString*)kSecClassKey, (__bridge NSString*)kSecAttrKeyType: (__bridge NSString*)kSecAttrKeyTypeRSA, - (__bridge NSString*)kSecAttrApplicationTag: tagData, + (__bridge NSString*)kSecAttrApplicationTag: tagData }; - SecItemDelete((__bridge CFDictionaryRef)removeAttributes); + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)removeAttributes); + if (status != errSecSuccess) { + if (error) { + *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; + } + } + return status != errSecSuccess; + } @end diff --git a/Sources/JWT/Supplement/JWTErrorDescription.m b/Sources/JWT/Supplement/JWTErrorDescription.m index 4ebefef5..0247078f 100644 --- a/Sources/JWT/Supplement/JWTErrorDescription.m +++ b/Sources/JWT/Supplement/JWTErrorDescription.m @@ -12,9 +12,10 @@ @implementation JWTErrorDescription + (NSDictionary *)userDescriptionsAndCodes { static NSDictionary *userDescriptionsAndCodes = nil; return userDescriptionsAndCodes ?: (userDescriptionsAndCodes = @{ + @(JWTUnexpectedError): @"JWT unexpected error", @(JWTInvalidFormatError): @"Invalid format! Try to check your encoding algorithm. Maybe you put too many dots as delimiters?", @(JWTUnsupportedAlgorithmError): @"Unsupported algorithm! You could implement it by yourself", - @(JWTAlgorithmNameMismatchError) : @"Algorithm doesn't match name in header.", + @(JWTAlgorithmNameMismatchError): @"Algorithm doesn't match name in header.", @(JWTInvalidSignatureError): @"Invalid signature! It seems that signed part of jwt mismatch generated part by algorithm provided in header.", @(JWTNoPayloadError): @"No payload! Hey, forget payload?", @(JWTNoHeaderError): @"No header! Hmm", @@ -27,17 +28,18 @@ + (NSDictionary *)userDescriptionsAndCodes { @(JWTBlacklistedAlgorithmError): @"Algorithm in blacklist? Try to check whitelist parameter", @(JWTDecodingHeaderError): @"Error decoding the JWT Header segment.", @(JWTDecodingPayloadError): @"Error decoding the JWT Payload segment.", - @(JWTDecodingHoldersChainEmptyError) : @"Error decoding the JWT algorithm and data holdersĀ chain is empty!", - @(JWTHolderSecretDataNotSetError) : @"Error encoding/decoding .secretData not set when using sign/verify keys. Bug. Workaround is simple. Set secretData: { holder.secretData([NSData data]); }" + @(JWTDecodingHoldersChainEmptyError): @"Error decoding the JWT algorithm and data holdersĀ chain is empty!", + @(JWTHolderSecretDataNotSetError): @"Error encoding/decoding .secretData not set when using sign/verify keys. Bug. Workaround is simple. Set secretData: { holder.secretData([NSData data]); }" }); } + (NSDictionary *)errorDescriptionsAndCodes { static NSDictionary *errorDescriptionsAndCodes = nil; return errorDescriptionsAndCodes ?: (errorDescriptionsAndCodes = @{ + @(JWTUnexpectedError): @"JWTUnexpectedError", @(JWTInvalidFormatError): @"JWTInvalidFormatError", @(JWTUnsupportedAlgorithmError): @"JWTUnsupportedAlgorithmError", - @(JWTAlgorithmNameMismatchError) :@"JWTAlgorithmNameMismatchError", + @(JWTAlgorithmNameMismatchError): @"JWTAlgorithmNameMismatchError", @(JWTInvalidSignatureError): @"JWTInvalidSignatureError", @(JWTNoPayloadError): @"JWTNoPayloadError", @(JWTNoHeaderError): @"JWTNoHeaderError", @@ -50,8 +52,8 @@ + (NSDictionary *)errorDescriptionsAndCodes { @(JWTBlacklistedAlgorithmError): @"JWTBlacklistedAlgorithmError", @(JWTDecodingHeaderError): @"JWTDecodingHeaderError", @(JWTDecodingPayloadError): @"JWTDecodingPayloadError", - @(JWTDecodingHoldersChainEmptyError) :@"JWTDecodingHoldersChainEmptyError", - @(JWTHolderSecretDataNotSetError) : @"JWTHolderSecretDataNotSetError" + @(JWTDecodingHoldersChainEmptyError): @"JWTDecodingHoldersChainEmptyError", + @(JWTHolderSecretDataNotSetError): @"JWTHolderSecretDataNotSetError" }); } diff --git a/Sources/JWT/include/JWT/JWTCryptoSecurity.h b/Sources/JWT/include/JWT/JWTCryptoSecurity.h index 39cee989..46f23a5f 100644 --- a/Sources/JWT/include/JWT/JWTCryptoSecurity.h +++ b/Sources/JWT/include/JWT/JWTCryptoSecurity.h @@ -25,7 +25,7 @@ + (SecKeyRef)addKeyWithData:(NSData *)data asPublic:(BOOL)public tag:(NSString *)tag type:(NSString *)type error:(NSError *__autoreleasing*)error; + (SecKeyRef)addKeyWithData:(NSData *)data asPublic:(BOOL)public tag:(NSString *)tag error:(NSError *__autoreleasing*)error; + (SecKeyRef)keyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error; -+ (void)removeKeyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error; ++ (BOOL)removeKeyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error; @end @interface JWTCryptoSecurity (Certificates) diff --git a/Sources/JWT/include/JWT/JWTErrorDescription.h b/Sources/JWT/include/JWT/JWTErrorDescription.h index 3b107d9e..a55da1ed 100644 --- a/Sources/JWT/include/JWT/JWTErrorDescription.h +++ b/Sources/JWT/include/JWT/JWTErrorDescription.h @@ -11,7 +11,8 @@ extern NSString *JWTErrorDomain; typedef NS_ENUM(NSInteger, JWTError) { - JWTInvalidFormatError = -100, + JWTUnexpectedError = -99, + JWTInvalidFormatError, JWTUnsupportedAlgorithmError, JWTAlgorithmNameMismatchError, JWTInvalidSignatureError, From a8b5823ef6fcc0e8167cf021f17b322c9c844688 Mon Sep 17 00:00:00 2001 From: Dmitry Lobanov Date: Tue, 8 Jun 2021 22:31:15 +0300 Subject: [PATCH 2/4] sources: algorithms crypto security extract identity and trust incomplete pkcs12 case has been handled. By Andreas Holm. --- .../JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m b/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m index eeae2357..a91eabf1 100644 --- a/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m +++ b/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m @@ -197,6 +197,14 @@ + (OSStatus)extractIdentityAndTrustFromPKCS12:(CFDataRef)inPKCS12Data password:( optionsDictionary, &items); // 2 + /** + @discussion + If a pkcs12 that was created with only one private key in it and no certificate was tried used, this just crashed when accessing index 0 with the CFArrayGetValueAtIndex. + */ + if (CFArrayGetCount(items) == 0) { + securityError = errSecPkcs12VerifyFailure; + } + // if (securityError == 0) { // 3 CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0); From ab86175d22e57f7efda38bfff7a93db45c321269 Mon Sep 17 00:00:00 2001 From: Dmitry Lobanov Date: Tue, 8 Jun 2021 23:17:54 +0300 Subject: [PATCH 3/4] sources: algorithms crypto security extract identity and trust incomplete pkcs12 case nil items guard has been added. --- Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m b/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m index a91eabf1..24fad29a 100644 --- a/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m +++ b/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m @@ -201,9 +201,9 @@ + (OSStatus)extractIdentityAndTrustFromPKCS12:(CFDataRef)inPKCS12Data password:( @discussion If a pkcs12 that was created with only one private key in it and no certificate was tried used, this just crashed when accessing index 0 with the CFArrayGetValueAtIndex. */ - if (CFArrayGetCount(items) == 0) { - securityError = errSecPkcs12VerifyFailure; - } + if (items == nil || CFArrayGetCount(items) == 0) { + securityError = errSecPkcs12VerifyFailure; + } // if (securityError == 0) { // 3 From 82ab9323939cfcb90cf65a05ee0cc4559c26f02f Mon Sep 17 00:00:00 2001 From: Dmitry Lobanov Date: Tue, 8 Jun 2021 23:23:06 +0300 Subject: [PATCH 4/4] sources: algorithms crypto security extract identity and trust incomplete pkcs12 case items guard has been enhanced. --- Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m b/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m index 24fad29a..4f0eefd0 100644 --- a/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m +++ b/Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m @@ -201,7 +201,7 @@ + (OSStatus)extractIdentityAndTrustFromPKCS12:(CFDataRef)inPKCS12Data password:( @discussion If a pkcs12 that was created with only one private key in it and no certificate was tried used, this just crashed when accessing index 0 with the CFArrayGetValueAtIndex. */ - if (items == nil || CFArrayGetCount(items) == 0) { + if (items != nil && CFArrayGetCount(items) == 0) { securityError = errSecPkcs12VerifyFailure; }