美文网首页
iOS 利用NSURLSession 对HTTPS进行双向认证

iOS 利用NSURLSession 对HTTPS进行双向认证

作者: IT搬运工 | 来源:发表于2016-12-06 16:43 被阅读0次

    前段是时间做项目要求进行双向认证,网上的查了很多都是不全的,今天将我整理之后的分享给大家。

    废话不多说直接上最主要的代码(这里主要是在NSURLSession的 didReceiveChallenge: 代理方法里进行操作)。


    // 当对https请求时都会走此代理

    ```

    - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge

    completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler

    {

    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;

    NSURLCredential *credential = nil;

    // 服务器验证

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])

    {

    /* 调用自定义的验证过程 */

    if ([self myCustomValidation:challenge]) {

    credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];

    if (credential) {

    disposition = NSURLSessionAuthChallengeUseCredential;

    }

    } else {

    /* 无效的话,取消 */

    disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;

    }

    }else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate])

    {//客户端认证

    NSString *thePath = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];

    NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];

    CFDataRef inPKCS12Data = (CFDataRef)CFBridgingRetain(PKCS12Data);

    SecIdentityRef identity;

    // 读取p12证书中的内容

    OSStatus result = [self extractP12Data:inPKCS12Data toIdentity:&identity];

    if(result != errSecSuccess){

    completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);

    return;

    }

    SecCertificateRef certificate = NULL;

    SecIdentityCopyCertificate (identity, &certificate);

    const void *certs[] = {certificate};

    CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);

    credential = [NSURLCredential credentialWithIdentity:identity certificates:(NSArray*)CFBridgingRelease(certArray) persistence:NSURLCredentialPersistencePermanent];

    if (credential) {

    disposition = NSURLSessionAuthChallengeUseCredential;

    }

    }

    if (completionHandler) {

    completionHandler(disposition, credential);

    }

    }

    ```

    -(OSStatus) extractP12Data:(CFDataRef)inP12Data toIdentity:(SecIdentityRef*)identity {

    OSStatus securityError = errSecSuccess;

    CFStringRef password = CFSTR("the_password");//证书密码

    const void *keys[] = { kSecImportExportPassphrase };

    const void *values[] = { password };

    CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);

    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);

    securityError = SecPKCS12Import(inP12Data, options, &items);

    if (securityError == 0) {

    CFDictionaryRef ident = CFArrayGetValueAtIndex(items,0);

    const void *tempIdentity = NULL;

    tempIdentity = CFDictionaryGetValue(ident, kSecImportItemIdentity);

    *identity = (SecIdentityRef)tempIdentity;

    }

    if (options) {

    CFRelease(options);

    }

    return securityError;

    }

    ```

    - (BOOL)myCustomValidation:(NSURLAuthenticationChallenge *)challenge

    {

    //获取trust object

    SecTrustRef trust = challenge.protectionSpace.serverTrust;

    SecTrustResultType result;

    //导入证书

    NSString * cerPath = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"cer"];; //证书的路径

    NSData * cerData = [NSData dataWithContentsOfFile:cerPath];

    SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(cerData));

    NSMutableArray *trustedCertificates = [NSMutableArray new];

    [trustedCertificates addObject:(__bridge_transfer id )(certificate)];

    //trustedCertificates = @[CFBridgingRelease(certificate)];

    //注意:这里将之前导入的证书设置成下面验证的Trust Object的anchor certificate

    SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)trustedCertificates);

    //2)SecTrustEvaluate会查找前面SecTrustSetAnchorCertificates设置的证书或者系统默认提供的证书,对trust进行验证

    OSStatus status = SecTrustEvaluate(trust, &result);

    if (status == errSecSuccess &&

    (result == kSecTrustResultProceed ||

    result == kSecTrustResultUnspecified)){

    return YES;

    }

    return NO;

    }

    ```

    相关文章

      网友评论

          本文标题:iOS 利用NSURLSession 对HTTPS进行双向认证

          本文链接:https://www.haomeiwen.com/subject/fgwhpttx.html