Swift iOS Client Certificate Authentication -
the web service want consume requires client certificate. how can send certificate it?
to further elaborate don't understand how create secidentityref
.
in nsurlconnection
didreceiveauthenticationchallenge
i've got conditional after servertrust
:
else if challenge?.protectionspace.authenticationmethod == nsurlauthenticationmethodclientcertificate { var secident : secidentityref = ????????? var certcred = nsurlcredential(identity: secident, certificates: [getclientcertificate()], persistence: nsurlcredentialpersistence.permanent) challenge?.sender.usecredential(certcred, forauthenticationchallenge: challenge!) }
the getclientcertificate
method:
func getclientcertificate() -> seccertificateref { let mainbundle : nsbundle = nsbundle.mainbundle() var mainbund = mainbundle.pathforresource("iosclientcert", oftype: "cer") //exported cert in der format. var key : nsdata = nsdata(contentsoffile: mainbund!)! var turntocert : seccertificateref = seccertificatecreatewithdata(kcfallocatordefault, key).takeretainedvalue() return turntocert; }
technically, when know needed implementation in swift, used following objective-c implementation in order nsurlcredential object connection; based on private key , x509 certificate pair contained in pkcs12 keystore.
sorry, don't have access source swift solution. know nsurlcredential returned swift, , used directly in http url connection there. it's similar one, though.
i'm not ios dev won't able out "bridging swift" part.
- (void)getmessagewithurl:(nsstring *)url { nsurl *url = [nsurl urlwithstring:url]; nsmutableurlrequest *request = [[nsmutableurlrequest alloc] init]; [request seturl:url]; [request sethttpmethod:@"get"]; nsurlconnection *connection = [[nsurlconnection alloc] initwithrequest:request delegate:self]; [connection self]; } - (void)postmessagewithurl:(nsstring *)url withcontent:(nsstring *)content { nsdata *postdata = [content datausingencoding:nsutf8stringencoding]; nsstring *postlength = [nsstring stringwithformat:@"%d", [postdata length]]; nsurl *myurl = [nsurl urlwithstring:url]; nsmutableurlrequest *request = [nsmutableurlrequest requestwithurl:myurl cachepolicy:nsurlrequestreloadignoringlocalcachedata timeoutinterval:60]; [request sethttpmethod:@"post"]; [request setvalue:postlength forhttpheaderfield:@"content-length"]; [request setvalue:@"application/json" forhttpheaderfield:@"content-type"]; [request sethttpbody:postdata]; nsurlconnection *connection = [[nsurlconnection alloc] initwithrequest:request delegate:self]; [connection self]; } - (bool)connection:(nsurlconnection *)connection canauthenticateagainstprotectionspace:(nsurlprotectionspace *)protectionspace { return [protectionspace.authenticationmethod isequaltostring:nsurlauthenticationmethodservertrust]; } - (void)connection:(nsurlconnection *)connection didreceiveauthenticationchallenge:(nsurlauthenticationchallenge *)challenge { nslog(@"didreceiveauthenticationchallenge"); } - (void)connection:(nsurlconnection *)connection didreceiveresponse:(nsurlresponse *)response { responsedata = [[nsmutabledata alloc] init]; } - (void)connection:(nsurlconnection *)connection didreceivedata:(nsdata *)data { [responsedata appenddata:data]; } - (void)connection:(nsurlconnection *)connection didfailwitherror:(nserror *)error { nslog(@"unable fetch data"); nslog(@"%@", error); } - (void)connectiondidfinishloading:(nsurlconnection *)connection { nslog(@"succeeded! received %lu bytes of data", (unsigned long)[responsedata length]); nsstring *responsestring = [[nsstring alloc] initwithdata:responsedata encoding:nsutf8stringencoding]; nslog(@"%@", responsestring); [bridge callhandler:handlername data:responsestring]; } - (void)connection:(nsurlconnection *)connection willsendrequestforauthenticationchallenge:(nsurlauthenticationchallenge *)challenge { /* reading certificate , creating identity */ nsarray *paths = nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes); nsstring *documentsdirectory = paths[0]; // documents directory nsdata *p12data = [certificatemanager getp12data]; //returns byte array containing valid pkcs12 certificate if (!p12data) { return; nsassert(p12data, @"couldn't load p12 file..."); } cfstringref password = cfstr("password"); const void *keys[] = {ksecimportexportpassphrase}; const void *values[] = {password}; cfdictionaryref optionsdictionary = cfdictionarycreate(null, keys, values, 1, null, null); cfarrayref p12items; osstatus result = secpkcs12import((__bridge cfdataref) p12data, optionsdictionary, &p12items); if (result == noerr) { cfdictionaryref identitydict = cfarraygetvalueatindex(p12items, 0); secidentityref identityapp = (secidentityref) cfdictionarygetvalue(identitydict, ksecimportitemidentity); seccertificateref certref; secidentitycopycertificate(identityapp, &certref); seccertificateref certarray[1] = {certref}; cfarrayref mycerts = cfarraycreate(null, (void *) certarray, 1, null); cfrelease(certref); nsurlcredential *credential = [nsurlcredential credentialwithidentity:identityapp certificates:nil persistence:nsurlcredentialpersistencenone]; cfrelease(mycerts); [[challenge sender] usecredential:credential forauthenticationchallenge:challenge]; } else { // certificate invalid or password invalid given certificate nslog(@"invalid certificate or password"); nserror *error = [nserror errorwithdomain:nsosstatuserrordomain code:result userinfo:nil]; return; } }
edit: har har, funny, downvoting me twice when didn't bother while bounty up. *grumble *
anyways, use following above, need access swift.
func connection(connection: nsurlconnection, willsendrequestforauthenticationchallenge challenge: nsurlauthenticationchallenge) { if let p12data = usermanager.currentp12, let credential = certificatemanager.getcredentialsforp12(p12data) as? nsurlcredential { challenge.sender.usecredential(credential, forauthenticationchallenge: challenge) } else { uiapplication.sharedapplication().networkactivityindicatorvisible = false } }
that uses this.
+ (id)getcredentialsforp12:(nsdata *)p12 { nsdata* p12data = p12; const void *keys[] = {ksecimportexportpassphrase}; const void *values[] = {cfstr("thepassword")}; cfdictionaryref optionsdictionary = cfdictionarycreate(null, keys, values, 1, null, null); cfarrayref p12items; osstatus result = secpkcs12import((__bridge cfdataref) p12data, optionsdictionary, &p12items); if (result == noerr) { cfdictionaryref identitydict = cfarraygetvalueatindex(p12items, 0); secidentityref identityapp = (secidentityref) cfdictionarygetvalue(identitydict, ksecimportitemidentity); seccertificateref certref; secidentitycopycertificate(identityapp, &certref); seccertificateref certarray[1] = {certref}; cfarrayref mycerts = cfarraycreate(null, (void *) certarray, 1, null); cfrelease(certref); nsurlcredential *credential = [nsurlcredential credentialwithidentity:identityapp certificates:nil persistence:nsurlcredentialpersistencenone]; cfrelease(mycerts); return credential; } else { // certificate invalid or password invalid given certificate nslog(@"invalid certificate or password"); uialertview* av = [[uialertview alloc] initwithtitle:@"error" message:@"invalid cert or pass" delegate:nil cancelbuttontitle:@"ok" otherbuttontitles: nil]; [av show]; nserror *error = [nserror errorwithdomain:nsosstatuserrordomain code:result userinfo:nil]; return nil; }
edit: swift version of above here, although messy enough rather didn't use it.
var p12items : unmanaged<cfarrayref>? let index: cfindex = 1 let password: cfstring = "password" let key = ksecimportexportpassphrase.takeretainedvalue() string var values = [unsafeaddressof(password)] var keys = [unsafeaddressof(key)] var keycallbacks = kcftypedictionarykeycallbacks var valuecallbacks = kcftypedictionaryvaluecallbacks let length: cfindex = p12data.length let p12cfdata: cfdata = cfdatacreate(kcfallocatordefault, unsafepointer<uint8>(p12data.bytes), length) let options = cfdictionarycreate(kcfallocatordefault, &keys, &values, index, &keycallbacks, &valuecallbacks) let result = secpkcs12import(p12cfdata, options, &p12items) if result == noerr { let idindex: cfindex = 0 var items = p12items?.takeretainedvalue() var identitydict = cfarraygetvalueatindex(items!, idindex) var key = ksecimportitemidentity.takeretainedvalue() string var keyaddress = unsafeaddressof(key) var identityapp: secidentityref = cfdictionarygetvalue(identitydict, keyaddress) var certref : unmanaged<seccertificateref>? secidentitycopycertificate(identityapp, &certref) var cert: seccertificateref = certref!.takeretainedvalue() var certarray = [unsafeaddressof(cert)] var arraycallback = kcftypearraycallbacks var mycerts: cfarrayref = cfarraycreate(kcfallocatordefault, &certarray, index, &arraycallback); let credential: nsurlcredential = nsurlcredential(identity: identityapp, certificates: [anyobject](), persistence: nsurlcredentialpersistence.none)
Comments
Post a Comment