Maciej Swic Maciej Swic - 1 month ago 16
Objective-C Question

Verifying the SSL certificate on iOS

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

Answer Source

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:

Safari certificate fingerprint

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.