iOS uses self-signed certificates for HTTPS requests

Source: Internet
Author: User
Tags ssl certificate

Since Apple has stipulated that all apps use HTTPS for network requests after January 1, 2017, they won't be able to get shelves, so we've studied the implementation of HTTPS requests in iOS. I believe that everyone on the https are more or less understand, here I will no longer introduce, the main function is to transmit the message encryption, improve security.

1. Certificate Preparation

There are two kinds of certificates, one is to pay for the certification of the Agency to purchase the certificate, the server if the use of such a certificate, the general client does not need to do, the request on the HTTPS to the line, Apple built up those trusted root certificate. The other is a self-made certificate, which is untrusted (and of course not paid for), so we need to set the certificate as a trusted certificate in the code.

I use Xca to create the root certificate, the production process please refer to http://www.2cto.com/Article/201411/347512.html, Since XCA cannot export the. Jsk suffix, we only have to export the root certificate in. p12 format, and the subsequent certificate production is done by the command line. Homemade a batch file, add the following command:

Set ip=%1%
MD%ip%
Keytool-importkeystore-srckeystore ca.p12 -srcstoretype Pkcs12-srcstorepass 123456 -destkeystore ca.jks-deststoretype jks-deststorepass 123456
Keytool-genkeypair-alias server-%ip%-keyalg rsa-keystore ca.jks-storepass 123456 - Keypass 123456 -validity 3650-dname "cn=%ip%, Ou=ly, O=hik, L=hz, St=zj, C=CN"
Keytool-certreq-alia s server-%ip%-storepass 123456 -file%ip%\server-%ip%.certreq-keystore ca.jks
Keytool-gencert- Alias Ca-storepass 123456 -infile%ip%\server-%ip%.certreq-outfile%ip%\server-%ip%.cer-validity 3650-keystore ca.jks 
Keytool-importcert-trustcacerts-storepass 123456 -alias server-%ip% -file%ip%\server-%ip%.cer-keystore ca.jks
Keytool-delete-keystore ca.jks-alias ca-storepass 123456

Change the bold ca.p12 to the name of the. p12 file you exported, and change the password for the certificate you created with 123456.

Then press and hold Ctrl+shift in the blank of the folder, right-click, select here to open the Command window, enter "start.bat ip/domain name" in the command window to execute the batch file, where Start.bat is the batch file that added the above command, ip/ The domain name is the IP or domain name of your server. After successful execution, a. jks file is generated and a folder named after your IP or domain name has a. cer certificate in the folder, and the. jks file on this side will use the. cer file on the server to be used at the client, where the certificate preparation is completed.

2. Service-side configuration

Because I do not do the service for many years, only use Tomcat, so this side only talk about the Tomcat configuration method, the other server's classmates please find the setting method on their own.

Open the Server.xml file in the tomcat/conf directory to open the configuration for HTTPS and configure it as follows:

<connector uriencoding= "UTF-8" protocol= "Org.apache.coyote.http11.Http11NioProtocol" port= "8443" maxthreads= " "Scheme=" https "secure=" true "sslenabled=" true "sslprotocol=" TLSv1.2 "sslenabledprotocols=" TLSv1.2 "Keystorefile = "${catalina.base}/ca/ca.jks" keystorepass= "123456" clientauth= "false" sslverifyclient= "off" netzone= "Your IP or domain name"/ >

Keystorefile is the directory where your. jks file is placed, Keystorepass is the password you set when you make the certificate, Netzone fill in your IP or domain name. Note that Apple requires an agreement to TLSv1.2 above .

3. iOS side configuration

First add the previously generated. cer file to your project, and be careful to select the targets you want to add when you add it.

1. Using Nsurlsession for requests

The code is as follows:

NSString *urlstring = @ "Https://xxxxxxx";
Nsurl *url = [Nsurl urlwithstring:urlstring];
Nsmutableurlrequest *request = [Nsmutableurlrequest requestwithurl:url cachepolicy: Nsurlrequestreloadignoringcachedata timeoutinterval:10.0f];
Nsurlsession *session = [Nsurlsession sessionwithconfiguration:[nsurlsessionconfiguration Defaultsessionconfiguration] delegate:self delegatequeue:[nsoperationqueue Mainqueue]];
Nsurlsessiondatatask *task = [session datataskwithrequest:request];
[Task resume];

You need to implement Nsurlsessiondatadelegate in the URLSession:didReceiveChallenge:completionHandler: method to verify the certificate, the code is as follows:

-(void) Urlsession: (Nsurlsession *) session Didreceivechallenge: (Nsurlauthenticationchallenge *) challenge
Completionhandler: (void (^) (nsurlsessionauthchallengedisposition disposition, nsurlcredential * _Nullable credential )) Completionhandler {
NSLog (@ "certificate Authentication");
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), please replace your certificate name
*/
NSString *cerpath = [[NSBundle mainbundle] pathforresource:@ "CA" oftype:@ "CER"];//self-signed certificate
nsdata* CaCert = [NSData Datawithcontentsoffile:cerpath];

Nscassert (CaCert! = nil, @ "CaCert is nil");
if (nil = = CaCert)
Break /* Failed */

Seccertificateref caref = Seccertificatecreatewithdata (NULL, (__bridge cfdataref) caCert);
Nscassert (caref! = nil, @ "Caref is nil");
if (nil = = Caref)
Break /* Failed */

You can add more than one certificate
Nsarray *caarray = @[(__bridge ID) (CAREF)];

Nscassert (Caarray! = nil, @ "Caarray is nil");
if (nil = = Caarray)
Break /* Failed */

Set the read certificate to the root certificate of the server-side frame number
Osstatus status = Sectrustsetanchorcertificates (Servertrust, (__bridge cfarrayref) caarray);
Nscassert (errsecsuccess = = status, @ "Sectrustsetanchorcertificates failed");
if (! ( Errsecsuccess = = status))
Break /* Failed */

Sectrustresulttype result =-1;
Verify that the server's certificate is trustworthy by using a locally imported certificate
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");
}

/* Ksectrustresultunspecified and Ksectrustresultproceed are success */
if (! Allowconnect)
{
Break /* Failed */
}

#if 0
/* Treat Ksectrustresultconfirm and Ksectrustresultrecoverabletrustfailure as success */
/* Since the user would likely tap-through to see the dancing bunnies * *
if (result = = Ksectrustresultdeny | | result = = Ksectrustresultfataltrustfailure | | result = = ksectrustresultothererror)
Break /* Failed to trust cert (good in the case) */
#endif

The only good exit point
NSLog (@ "Trust this Certificate");

Nsurlcredential *credential = [nsurlcredential credentialForTrust:challenge.protectionSpace.serverTrust];
Completionhandler (nsurlsessionauthchallengeusecredential,credential);
return [[Challenge Sender] Usecredential:credential
Forauthenticationchallenge:challenge];

}
while (0);
}

Bad Dog
Nsurlcredential *credential = [nsurlcredential credentialForTrust:challenge.protectionSpace.serverTrust];
Completionhandler (nsurlsessionauthchallengecancelauthenticationchallenge,credential);
return [[Challenge Sender] cancelauthenticationchallenge:challenge];
}

The server can be successfully requested at this time.

Note: Calling Sectrustsetanchorcertificates to set the list of trusted certificates will only validate in the list of settings and will mask the system's original trust list. For the system to continue to function as long as the Sectrustsetanchorcertificates method is called, the second parameter is set to No.

2. Using Afnetworking for requests

Afnetworking first needs to configure the Afsecuritypolicy class, and the Afsecuritypolicy class encapsulates the process of certificate validation.

/**
Afsecuritypolicy three types of authentication modes:
Afsslpinningmodenone: Just verify that the certificate is in the trust list
Afsslpinningmodecertificate: This mode verifies that the certificate is in the trust list, and then compares the server-side certificate and the client certificate for consistency
Afsslpinningmodepublickey: Verify that the server-side certificate is consistent with the public key of the client certificate
*/

Afsecuritypolicy *securitypolicy = [Afsecuritypolicy policywithpinningmode:afsslpinningmodecertificate];
Securitypolicy.allowinvalidcertificates = yes;//Whether to allow self-signed certificates
Securitypolicy.validatesdomainname = no;//need to verify domain name, default Yes

Afhttpsessionmanager *_manager = [Afhttpsessionmanager manager];
_manager.responseserializer = [Afhttpresponseserializer serializer];
_manager.securitypolicy = securitypolicy;
Set timeout
[_manager.requestserializer willchangevalueforkey:@ "timeOutInterval"];
_manager.requestserializer.timeoutinterval = 20.F;
[_manager.requestserializer didchangevalueforkey:@ "timeOutInterval"];
_manager.requestserializer.cachepolicy = Nsurlrequestreloadignoringcachedata;
_manager.responseserializer.acceptablecontenttypes = [Nsset setwithobjects:@ "Application/xml", @ "Text/xml", @ "text/ Plain ", @" Application/json ", nil];

__weak typeof (self) weakself = self;
[_manager setsessiondidreceiveauthenticationchallengeblock:^nsurlsessionauthchallengedisposition (NSURLSession * Session, Nsurlauthenticationchallenge *challenge, nsurlcredential *__autoreleasing *_credential) {

Sectrustref servertrust = [[Challenge Protectionspace] servertrust];
/**
* Import multiple CA certificates
*/
NSString *cerpath = [[NSBundle mainbundle] pathforresource:@ "CA" oftype:@ "CER"];//self-signed certificate
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");

nsurlsessionauthchallengedisposition disposition = nsurlsessionauthchallengeperformdefaulthandling;
__autoreleasing nsurlcredential *credential = nil;
if ([Challenge.protectionSpace.authenticationMethod Isequaltostring:nsurlauthenticationmethodservertrust]) {
if ([WeakSelf.manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust Fordomain: Challenge.protectionSpace.host]) {
credential = [Nsurlcredential credentialForTrust:challenge.protectionSpace.serverTrust];
if (credential) {
disposition = nsurlsessionauthchallengeusecredential;
} else {
disposition = nsurlsessionauthchallengeperformdefaulthandling;
}
} else {
disposition = Nsurlsessionauthchallengecancelauthenticationchallenge;
}
} else {
disposition = nsurlsessionauthchallengeperformdefaulthandling;
}

return disposition;
}];

The code above validates the certificate itself by re-setting the certificate validation callback to Afhttpsessionmanager and then joins its own certificate to the list of trusted certificates, which can be verified by the certificate.

Because the server is using. JKS is a certificate library, the client obtains more than one certificate, I got two here, the basic can be obtained through the Sectrustgetcertificatecount method of the number of certificates, afnetworking in Evaluateservertrus T:fordomain: In the method, Afsslpinningmode is the same type as afsslpinningmodecertificate and Afsslpinningmodepublickey, the number of certificates on the server is the same as how many certificates the client trusts. If not the same can not be requested to succeed, so I will modify his source code, when there is a verification success is counted.

When the type is Afsslpinningmodecertificate

return Trustedcertificatecount = = [Servercertificates count]-1;

When the Afsslpinningmodepublickey

Return trustedpublickeycount > 0 && ((self.validatescertificatechain) | | (!self.validatescertificatechain && trustedpublickeycount >= 1));

The condition of Trustedpublickeycount = = [Servercertificates count] in the second block is removed.

The version of afnetworking used here is 2.5.3, if the other version is different, please modify it according to the actual situation.

Demo Address: Https://github.com/fengling2300/networkTest



Wave cast King
Links: Http://www.jianshu.com/p/e6a26ecd84aa
Source: Pinterest
Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please specify the source.

iOS uses self-signed certificates for HTTPS requests

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.