iOS development HTTPS implementation of trusted SSL and self-signed certificates

Source: Internet
Author: User
Tags ssl certificate subdomain name



Let's start by analyzing what HTTPS is and what it means for iOS developers


HTTPS and SSL/TSL
    • What is SSL?


SSL (secure Sockets layer), because the HTTP protocol used on the internet is plaintext, there are many drawbacks, such as the transmission of content will be peeping (sniffing) and tampering. The purpose of the SSL protocol is to encrypt the network connection at the transport layer.


    • What is TLS?


By the year 1999, SSL has become a de facto standard on the Internet because of its wide application. The IETF standardized SSL in that year. After normalization, the name is changed to TLS (Transport layer Security, Transport Layer secure Protocol). SSL and TLS can be seen as different stages of the same thing


    • HTTPS


Simply put, HTTPS = http + SSL/TLS, or HTTP over SSL or HTTP over TLS, which is the origin of the following S.



HTTPS and HTTP similarities and differences: HTTP and HTTPS use a completely different way of connection, with the same port, the former is 80, the latter is 443. The HTTP connection is simple and stateless; The HTTPS protocol is a network protocol built by the SSL+HTTP protocol for encrypted transmission and authentication, which is more secure than the HTTP protocol.



At the WWDC 2016 developer conference, Apple announced a deadline: The app Transport security feature must be enabled for all apps in the App Store by January 1, 2017. APP Transport Security (ATS) is a privacy protection feature introduced by Apple in iOS 9, which blocks plaintext HTTP resources from loading, and connections must be more secure HTTPS. Apple currently allows developers to continue to use HTTP connections for the time being, but the use of ATS must be mandatory for all official stores by the end of the year.



The following is the original version of the developer website:


The Application Transport security protocol is published with iOS9 and OS X 10.11, which requires the application to use a secure network connection over HTTPS to improve the user's data and privacy security.
On the 2016 WWDC we announced that before the end of the year, applications submitted to the App store must support the application Transport security protocol. In order to give you extra time to prepare, this deadline has been extended and we will provide timely information when the new deadlines are determined.


December 21, 2016 Apple updated its due date and announced the postponement of the implementation of ATS support requirements supporting APP Transport Security.


Developer site


* * This provides developers with more time to adapt and support. However, for iOS developers, it is still best to fix HTTPS requests as early as possible. **



Requirements of the Apple ATS for HTTPS certificates


Enabling ATS must meet the following criteria, which do not meet the conditional HTTPS certificate, ATS will reject the connection:

    • Server-all connections using TLS1.2 or later
    • The HTTPS certificate must be signed with the hash algorithm above SHA256
    • HTTPS certificates must use RSA 2048-bit or ECC 256-bit public key algorithm
    • Using forward encryption technology


In addition, Apple ATS supports transparent CT certificates, requiring developers to use SSL certificates that support the transparency of CT certificates, to ensure that SSL certificates are legally transparent and to prevent man-in-the-middle attacks.


Send HTTPS requests to trust SSL and self-signed certificates in three scenarios


1. If your app server is SLL issued CA, you can use the system method to directly implement the trust SSL certificate, about Apple's requirements for SSL certificate refer to: Apple Official document Certkeytrustprogguide



This way does not need to introduce a CA file in the bundle, can be handed over to the system to determine whether the server-side certificate is SSL certificate, the verification process does not require us to implement the specific.
Example code:

NSURL * URL = [NSURL URLWithString: URLString];
    NSURLRequest * request = [[NSURLRequest alloc] initWithURL: URL cachePolicy: NSURLRequestReloadIgnoringLocalCacheData timeoutInterval: 10];
    // Create synchronous connection
    NSError * error = nil;
    NSData * receivedData = [NSURLConnection sendSynchronousRequest: request returningResponse: nil error: & error];
    NSString * receivedInfo = [[NSString alloc] initWithData: receivedData encoding: NSUTF8StringEncoding];
Of course, if you need to trust both the SSL certificate and the self-signed certificate, you still need to implement CA verification in the code. This situation will be mentioned later.

2. Based on AFNetWorking's SSL specific server certificate trust processing, rewriting AFNetWorking's customSecurityPolicy method, here I created an HttpRequest class to encapsulate the GET and POST methods, taking the GET method as an example:



+ (void) get: (NSString *) url params: (NSDictionary *) params success: (void (^) (id)) success failure: (void (^) (NSError *)) failure {
    // 1. Get the request manager
    AFHTTPRequestOperationManager * mgr = [AFHTTPRequestOperationManager manager];
    // 2. Affirm that the returned result is of type text / html
    mgr.responseSerializer = [AFHTTPResponseSerializer serializer];
    // 3. Set the timeout time to 10s
    mgr.requestSerializer.timeoutInterval = 10;
    
    // With this line of code, https ssl verified.
    if (openHttpsSSL) {
        [mgr setSecurityPolicy: [self customSecurityPolicy]];
    }
    
    // 4. Send GET request
    [mgr GET: url parameters: params success: ^ (AFHTTPRequestOperation * operation, id responseObj) {
        if (success) {
            success (responseObj);
        }
    } failure: ^ (AFHTTPRequestOperation * operation, NSError * error) {
        if (error) {
            failure (error);
        }
    }];
}
+ (AFSecurityPolicy *) customSecurityPolicy {
    /// Import the certificate first
    NSString * cerPath = [[NSBundle mainBundle] pathForResource: certificate ofType: @ "cer"]; // The path of the certificate
    NSData * certData = [NSData dataWithContentsOfFile: cerPath];
    
    // AFSSLPinningModeCertificate uses certificate verification mode
    AFSecurityPolicy * securityPolicy = [AFSecurityPolicy policyWithPinningMode: AFSSLPinningModeCertificate];
    
    // allowInvalidCertificates whether to allow invalid certificates (that is, self-built certificates), the default is NO
    // If you need to verify the self-built certificate, you need to set it to YES
    securityPolicy.allowInvalidCertificates = YES;
    
    // validatesDomainName needs to verify the domain name, the default is YES;
    // If the domain name of the certificate is inconsistent with the domain name you request, you need to set this item to NO; if it is set to NO, the server can also establish a connection even if the server uses a certificate issued by another trusted organization. This is very dangerous and it is recommended to open it.
    // Set to NO, mainly used in this case: the client requests a subdomain name, and the certificate is another domain name. Because the domain name on the SSL certificate is independent, if the domain name registered on the certificate is www.google.com, then mail.google.com cannot be verified; of course, if you have money, you can register a wildcard domain name * .google.com, But this is still relatively expensive.
    // If set to NO, it is recommended to add the verification logic of the corresponding domain name.
    securityPolicy.validatesDomainName = NO;
    
    securityPolicy.pinnedCertificates = @ [certData];
    
    return securityPolicy;
}


The cerPath is the certificate path in the app bundle, and the certificate is the macro of the certificate name. It only supports the cer format. The relevant configuration of securityPolicy is particularly important. Please read the customSecurityPolicy method carefully and set its properties according to the actual situation.

In this way, you can use the HTTPS protocol to access a specific server on the basis of AFNetWorking, but you cannot trust the CA file of the root certificate. Therefore, this method has risks. It may fail when reading the certificate array in pinnedCertificates. If the certificate does not match, certData will be nil.

3. Change the system method and send an asynchronous NSURLConnection request.



-(void) getDataWithURLRequest {
    // connection
    NSString * urlStr = @ "https://developer.apple.com/cn/";
    NSURL * url = [NSURL URLWithString: urlStr];
    NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL: url cachePolicy: NSURLRequestUseProtocolCachePolicy timeoutInterval: 10];
    NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest: request delegate: self];
    [connection start];
}
The focus is on handling the didReceiveAuthenticationChallenge proxy method of NSURLConnection, verifying the CA file and establishing a trusted connection.


-(BOOL) connection: (NSURLConnection *) connection canAuthenticateAgainstProtectionSpace: (NSURLProtectionSpace *) protectionSpace {
    
    return [protectionSpace.authenticationMethod isEqualToString: NSURLAuthenticationMethodServerTrust];
}

-(void) connection: (NSURLConnection *) connection didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *) challenge {
    
 / *
    // Directly verify whether the server is authenticated (serverTrust). This method directly ignores certificate verification and directly establishes a connection, but cannot filter other URL connections. It can be understood as a compromise processing method, which is actually not safe, so it is not recommended. .
    SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
    return [[challenge sender] useCredential: [NSURLCredential credentialForTrust: serverTrust]
                  forAuthenticationChallenge: challenge];
     * /
    if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {
        do
        {
            SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
            NSCAssert (serverTrust! = Nil, @ "serverTrust is nil");
            if (nil == serverTrust)
                break; / * failed * /
            / **
             * Import multiple CA certificates (Certification Authority, support SSL certificate and self-signed CA)
             * /
            NSString * cerPath = [[NSBundle mainBundle] pathForResource: @ "cloudwin" ofType: @ "cer"]; // Self-signed certificate
            NSData * caCert = [NSData dataWithContentsOfFile: cerPath];
            
            NSString * cerPath2 = [[NSBundle mainBundle] pathForResource: @ "apple" ofType: @ "cer"]; // SSL certificate
            NSData * caCert2 = [NSData dataWithContentsOfFile: cerPath2];
            
            NSCAssert (caCert! = Nil, @ "caCert is nil");
            if (nil == caCert)
                break; / * failed * /
            
            NSCAssert (caCert2! = Nil, @ "caCert2 is nil");
            if (nil == caCert2) {
break;
            }
            
            SecCertificateRef caRef = SecCertificateCreateWithData (NULL, (__bridge CFDataRef) caCert);
            NSCAssert (caRef! = Nil, @ "caRef is nil");
            if (nil == caRef)
                break; / * failed * /
            
            SecCertificateRef caRef2 = SecCertificateCreateWithData (NULL, (__bridge CFDataRef) caCert2);
            NSCAssert (caRef2! = Nil, @ "caRef2 is nil");
            if (nil == caRef2)
                break; / * failed * /
            
            NSArray * caArray = @ [(__ bridge id) (caRef), (__ bridge id) (caRef2)];
        
            NSCAssert (caArray! = Nil, @ "caArray is nil");
            if (nil == caArray)
                break; / * failed * /
            
            OSStatus status = SecTrustSetAnchorCertificates (serverTrust, (__bridge CFArrayRef) caArray);
            NSCAssert (errSecSuccess == status, @ "SecTrustSetAnchorCertificates failed");
            if (! (errSecSuccess == status))
                break; / * failed * /
            
            SecTrustResultType result = -1;
            status = SecTrustEvaluate (serverTrust, & result);
            if (! (errSecSuccess == status))
                break; / * failed * /
            NSLog (@ "stutas:% d", (int) status);
            NSLog (@ "Result:% d", result);
            
            BOOL allowConnect = (result == kSecTrustResultUnspecified) || (result == kSecTrustResultProceed);
            if (allowConnect) {
                NSLog (@ "success");
            } else {
                NSLog (@ "error");
            }
            / * https://developer.apple.com/library/ios/technotes/tn2232/_index.html * /
            / * https://developer.apple.com/library/mac/qa/qa1360/_index.html * /
            / * kSecTrustResultUnspecified and kSecTrustResultProceed are success * /
            if (! allowConnect)
            {
            break; / * failed * /
            }
            
#if 0
            / * Treat kSecTrustResultConfirm and kSecTrustResultRecoverableTrustFailure as success * /
            / * since the user will likely tap-through to see the dancing bunnies * /
            if (result == kSecTrustResultDeny || result == kSecTrustResultFatalTrustFailure || result == kSecTrustResultOtherError)
                break; / * failed to trust cert (good in this case) * /
#endif
            
            // The only good exit point
            return [[challenge sender] useCredential: [NSURLCredential credentialForTrust: serverTrust]
                          forAuthenticationChallenge: challenge];
            
        } while (0);
    }
    
    // Bad dog
    return [[challenge sender] cancelAuthenticationChallenge: challenge];
    
}
The key here is the value of the result parameter. According to the description of the official document, judge the value of (result == kSecTrustResultUnspecified) || (result == kSecTrustResultProceed). If it is 1, the CA of the website is successfully trusted by the app and data can be established Connection, which means that all server certificates issued by the CA are trusted, and access to any website that is not trusted will fail to connect. The CA file can be either SLL or self-signed.

Implementation of other proxy methods of NSURLConnection


#pragma mark-Connect's asynchronous proxy method
-(void) connection: (NSURLConnection *) connection didReceiveResponse: (NSURLResponse *) response {
    NSLog (@ "Request was responded");
    _mData = [[NSMutableData alloc] init];
}

-(void) connection: (NSURLConnection *) connection didReceiveData: (nonnull NSData *) data {
    NSLog (@ "Start to return data fragments");
    
    [_mData appendData: data];
}

-(void) connectionDidFinishLoading: (NSURLConnection *) connection {
    NSLog (@ "Link completed");
    // Data can be parsed here
    NSString * receiveInfo = [NSJSONSerialization JSONObjectWithData: self.mData options: NSJSONReadingAllowFragments error: nil];
    NSLog (@ "received data: \\\\ n% @", self.mData);
    NSLog (@ "received info: \\\\ n% @", receiveInfo);
}

// Link error
-(void) connection: (NSURLConnection *) connection didFailWithError: (NSError *) error {
    NSLog (@ "error-% @", error);
}
At this point, the problem of HTTPS trust certificates has been resolved, not only in response to Apple's mandatory use of ATS, but also for the safety of the actual production environment. HTTPS is the future trend and it is recommended to support it as soon as possible.

If you need to refer to Demo, please move to my open source project on Github

Trust SSL certificate and self-signed certificate for iOS development HTTPS

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.