Is it possible to check the SSL certificate thumbprint on iOS?
Bonus round: Does the thumbprint change when i extend my certificate? Are there any special considerations when extending the certificate if verify the thumbprint?
Thanks
To verify the thumbprint/fingerprint, I use a category on NSURLAuthenticationChallenge
. You don't have to use a category or can use a different input but the code to get the fingerprint of a certificate would actually be the same.
NSURLAuthenticationChallenge+Fingerprint.h
@import Foundation;
@interface NSURLAuthenticationChallenge (Fingerprint)
- (NSString *)SHA1Fingerprint;
- (NSString *)MD5Fingerprint;
@end
NSURLAuthenticationChallenge+Fingerprint.m
#import "NSURLAuthenticationChallenge+Fingerprint.h"
#import <CommonCrypto/CommonCrypto.h>
typedef NS_ENUM(NSInteger, kFingerprintType) {
kFingerprintTypeSHA1,
kFingerprintTypeMD5
};
@implementation NSURLAuthenticationChallenge (Fingerprint)
- (NSString *)SHA1Fingerprint
{
return [self fingerprintWithType:kFingerprintTypeSHA1];
}
- (NSString *)MD5Fingerprint
{
return [self fingerprintWithType:kFingerprintTypeMD5];
}
- (NSString *)fingerprintWithType:(kFingerprintType)type
{
SecTrustRef serverTrust = [[self protectionSpace] serverTrust];
SecTrustResultType trustResultType;
SecTrustEvaluate(serverTrust, &trustResultType);
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, (SecTrustGetCertificateCount(serverTrust) - 1));
NSData *data = CFBridgingRelease(SecCertificateCopyData(certificate));
const NSUInteger length = [self lengthWithType:type];
unsigned char buffer[length];
switch (type) {
case kFingerprintTypeSHA1: {
CC_SHA1(data.bytes, (CC_LONG)data.length, buffer);
break;
}
case kFingerprintTypeMD5: {
CC_MD5(data.bytes, (CC_LONG)data.length, buffer);
break;
}
}
NSMutableString *fingerprint = [NSMutableString stringWithCapacity:length * 3];
for (int i = 0; i < length; i++) {
[fingerprint appendFormat:@"%02x ",buffer[i]];
}
return [fingerprint stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
- (NSUInteger)lengthWithType:(kFingerprintType)type
{
switch (type) {
case kFingerprintTypeSHA1: {
return CC_SHA1_DIGEST_LENGTH;
}
case kFingerprintTypeMD5: {
return CC_MD5_DIGEST_LENGTH;
}
}
}
With the example code:
#pragma mark - UIViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:@"YOUR_HTTPS_URL"];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// Do something meaningful
}];
[task resume];
}
#pragma mark - NSURLSessionDelegate
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
NSLog(@"%@", challenge.SHA1Fingerprint);
NSLog(@"%@", challenge.MD5Fingerprint);
}
// Do something meaningful
}
I would get the output:
2014-11-17 00:09:10.880 test[48237:2922518] f9 d5 24 c2 08 6b bf 12 6f 48 cd 8a f0 4d ca 3e 7c f0 3f bc
2014-11-17 00:09:10.880 test[48237:2922518] bf 30 1a 8d f9 cb 15 bd 51 73 c8 22 a5 54 62 8a
Safari can be used to verify the data:
Regarding the Extended Validation certificates, they're not a different type of certificates, they have the same mechanisms, but the certificate policies field will use a specific certificate policy identifier.
The fingerprint being the hash of the entire certificate, with any modifications (like using EV certificates), the fingerprint would be different but the process to get the fingerprint would be the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With