是否可以在iOS上检查SSL证书指纹?
奖金回合:当我延长证书时,指纹是否会改变?如果验证指纹,在扩展证书时是否有任何特殊注意事项?
由于
答案 0 :(得分:14)
要验证指纹/指纹,我在NSURLAuthenticationChallenge
上使用了一个类别。您不必使用类别或可以使用不同的输入,但获取证书指纹的代码实际上是相同的。
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;
}
}
}
使用示例代码:
#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
}
我会得到输出:
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可用于验证数据:
关于扩展验证证书,它们不是不同类型的证书,它们具有相同的机制,但证书策略字段将使用特定的证书策略标识符。
指纹是整个证书的散列,经过任何修改(如使用EV证书),指纹会有所不同,但获取指纹的过程也是一样的。
答案 1 :(得分:3)
对于那些感兴趣的人;这是Swift翻译的扩展名:
enum FingerprintType {
case SHA1
case MD5
}
extension NSURLAuthenticationChallenge {
func getSHA1Fingerprint() -> String {
return getFingerprintWithType(.SHA1)
}
func getMD5Fingerprint() -> String {
return getFingerprintWithType(.MD5)
}
private func getFingerprintWithType(type : FingerprintType) -> String {
var serverTrust = self.protectionSpace.serverTrust
SecTrustEvaluate(serverTrust, nil)
var certificate = SecTrustGetCertificateAtIndex(serverTrust, 0).takeUnretainedValue()
var data = SecCertificateCopyData(certificate).takeUnretainedValue() as NSData
let length = self.lengthWityType(type)
var buffer = [UInt8](count:Int(length), repeatedValue: 0)
switch(type) {
case .SHA1:
CC_SHA1(data.bytes, CC_LONG(data.length), &buffer)
break
case .MD5:
CC_MD5(data.bytes, CC_LONG(data.length), &buffer)
}
var fingerPrint = NSMutableString()
for byte in buffer {
fingerPrint.appendFormat("%02x ", byte)
}
return fingerPrint.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
}
private func lengthWityType(type : FingerprintType) -> Int32 {
switch type {
case .SHA1:
return CC_SHA1_DIGEST_LENGTH
case .MD5:
return CC_MD5_DIGEST_LENGTH
default:
return 0
}
}
}