At WWDC 2016, Apple said that from January 1, 2017, all new apps submitted must use HTTPS protocol to make web requests. Non-https network access is disabled by default and the ATS(App Transport) can no longer be bypassing by simply adding NSAllowsArbitraryLoads to info.plist Security) (otherwise must be stated during application review and will likely be rejected). So companies that have not yet done so need to move to HTTPS as soon as possible. This article will briefly describe HTTPS and the principle of configuring digital certificates and explain the configuration examples and problems, hoping to help you. (than heart ~)





HTTPS:

Simply put, HTTPS is THE SSL protocol with an additional layer of encryption on top of HTTP. Compared with HTTP, HTTPS ensures that the content is not viewed by a third party during transmission, that the content is tampered with by a third party in a timely manner, and that identity impersonation is prevented, thus ensuring network data security more effectively.

The interaction between the HTTPS client and the server is as follows: 1. When the client requests for the first time, the server returns a digital certificate containing the public key to the client. 2. The client generates a symmetric encryption key and encrypts it with the obtained public key and returns it to the server. 3. The server uses its own private key to decrypt the received encrypted data, obtain the symmetric encryption key and save it; 4. The two parties then transmit symmetrically encrypted data.





Digital Certificates:

When the HTTPS client interacts with the server for the first time, the server returns the digital certificate to the client so that the client can verify whether the digital certificate is sent by the server and whether the certificate is owned by the server to ensure that the data is not tampered with by a third party. A digital certificate can guarantee that the public key in the digital certificate is indeed the owner of the certificate (Subject), or that the certificate can be used to confirm the identity of the other party. A certificate consists of a public key, Subject, and digital signature. Digital signature is the security label of the certificate. Currently, SHA-RSA encryption is the most widely used.

Generally, certificates are classified into two types: one is a certificate purchased from an authoritative authority. When the server uses this certificate, the Apple system has its trusted signature root certificate built-in, so the client does not need additional configuration. To ensure certificate security, when a certificate issuer publishes a certificate, the fingerprint algorithm of the certificate is encrypted and published together with the certificate to prevent others from forging a digital certificate. The certificate authority uses its own private key to encrypt its fingerprint algorithm, which can be decrypted by the institutional signature root certificate built into the operating system to ensure the security of the certificate. The other is a self-signed certificate. The advantage is that you don’t have to pay for it, but you can’t be trusted with it, so you need to configure it as a trust certificate in your code. This is the main purpose of this article.

The specific implementation

When we use the self-signed certificate to implement HTTPS request, unlike the certificate issued by the institution, its signed root certificate has been built into the system, so we need to build our server’s signed root certificate into the App to verify the digital certificate. First, add the. Cer root certificate generated by the server to the project. Note that you must check targets before adding the certificate. One caveat here: Apple’s ATS requires server support for TLS 1.2 or above; A password that supports forward secrecy must be used; The certificate must be signed using the SHA-256 or better signed hash algorithm. If the certificate is invalid, the connection will fail. Because I signed when I was in generating the root certificate of the hash algorithm is lower than the requirement, after configuration request has been submitted to the NSURLErrorServerCertificateUntrusted = 1202 error, hope you can take note.

This article uses AFNetworking 3.0 to configure certificate verification. AFSecurityPolicy encapsulates the certificate verification process. AFSecurityPolicy points three authentication modes: 1, AFSSLPinningModeNone: validation certificate is only 2, AFSSLPinningModeCertificate in new list: Trust verification certificate is in the list, and then compare the server certificate and the client certificate are consistent, AFSSLPinningModePublicKey: Only verify that the public key of the server and client certificates is the same. Here we choose the second mode and set the AFSecurityPolicy allowInvalidCertificates and validatesDomainName. The AFSecurityPolicy configuration code is as follows:

AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; securityPolicy.allowInvalidCertificates = YES; / / is allowed to use a self-signed certificate securityPolicy. ValidatesDomainName = NO. Self. manager = [AFHTTPSessionManager manager]; self.manager.responseSerializer = [AFHTTPResponseSerializer serializer]; self.manager.securityPolicy = securityPolicy;Copy the code

When the server receives the client request, it may need to verify the client certificate, ask the client to provide the appropriate certificate, and then decide whether to return data. This is called challenge authentication, in which the public and private keys are authenticated by both parties. To implement client-side authentication, the manager must set methods that require authentication callbacks:

- (void)setSessionDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))blockCopy the code

And implement specific code to replace the default implementation of AFNetworking. Where challenge is the authentication challenge and block returns the configuration of the authentication request challenge. After receive the inquiry, the client according to the service side of the challenge to generate the required NSURLSessionAuthChallengeDisposition disposition and NSURLCredential * the credential. Disposition designated to deal with the inquiry method, and the credential is generated by the client inquiry certificate, pay attention to only challenge the authentication method for NSURLAuthenticationMethodServerTrust, only need to generate challenge certificate. Finally, respond to the server’s query.

The specific implementation code is as follows:

[self.manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing *_credential) {// Obtain the trust object SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust]; NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"ca" ofType:@"cer"];  NSData* caCert = [NSData dataWithContentsOfFile:cerPath]; NSArray *cerArray = @[caCert];  weakSelf.manager.securityPolicy.pinnedCertificates = cerArray;  SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert); NSCAssert(caRef ! = nil, @"caRef is nil"); NSArray *caArray = @[(__bridge id)(caRef)]; NSCAssert(caArray ! = nil, @"caArray is nil"); OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);  SecTrustSetAnchorCertificatesOnly(serverTrust,NO);  NSCAssert(errSecSuccess == status, @"SecTrustSetAnchorCertificates failed"); / / select inquiry certification handling NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;  __autoreleasing NSURLCredential *credential = nil; / / NSURLAuthenticationMethodServerTrust inquiry authentication if ([challenge. ProtectionSpace. AuthenticationMethod IsEqualToString: NSURLAuthenticationMethodServerTrust]) {/ / based on the client's security policies to decide whether to trust the server, don't trust does not respond to inquiries.  if ([weakSelf.manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust ForDomain: challenge. ProtectionSpace. Host]) {/ / create the inquiry the credential certificate = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; / / confirm the way of questioning the if (the credential) {disposition = NSURLSessionAuthChallengeUseCredential;  } else { disposition = NSURLSessionAuthChallengePerformDefaultHandling; }} else {/ / cancel the inquiry disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;  } } else { disposition = NSURLSessionAuthChallengePerformDefaultHandling; } return disposition; }];Copy the code

Note the #Warning in ViewController and NetworkManager, drag the certificate into the project, add the certificate name to NetworkManager, and add your URL to ViewController.

If there are any mistakes or omissions in this article, please leave comments and discuss.

Reference article:

Principles of digital Certificates Certificate, Key, App Transport Security(ATS) AFNetworking for HTTPS authentication IOS uses self-signed certificates to implement HTTPS requests