{"id":226,"date":"2013-05-25T09:44:10","date_gmt":"2013-05-25T08:44:10","guid":{"rendered":"http:\/\/oso.com.pl\/?p=226"},"modified":"2015-11-20T10:38:34","modified_gmt":"2015-11-20T09:38:34","slug":"blizniacze-certyfikaty-z-ios","status":"publish","type":"post","link":"https:\/\/oso.com.pl\/?p=226","title":{"rendered":"Bli\u017aniacze certyfikaty z iOS"},"content":{"rendered":"<p>Kolejny o certyfikatach. Powiedzmy, \u017ce piszesz aplikacj\u0119\u0099 na iOS, kt\u00f3ra ma uwierzytelnia\u0107\u0087 si\u0119 za pomoc\u0105 certyfikatu. Implementujesz co\u015b\u009b takiego:<\/p>\n<pre class=\"brush: objc; title: ; notranslate\" title=\"\">\r\n\r\n- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {\r\n if (&#x5B;challenge previousFailureCount] &gt; 0) {\r\n\r\nNSLog(@&quot;Incorrect auth challenge %@&quot;, challenge);\r\n &#x5B;&#x5B;challenge sender] cancelAuthenticationChallenge:challenge];\r\n return;\r\n }\r\n\r\n\/\/ Checking the server certificate\r\n if (&#x5B;&#x5B;challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate &amp;&amp;\r\n self.account.clientCertificate.privateRepresentation.length &gt; 0) {\r\n\r\n\/*\r\n Reading the certificate and creating the identity\r\n *\/\r\n\r\nNSData *p12Data = self.account.clientCertificate.privateRepresentation;\r\n\r\nCFStringRef password = (__bridge CFStringRef)(self.account.clientCertificate.privatePassword);\r\n const void *keys&#x5B;] = { kSecImportExportPassphrase };\r\n const void *values&#x5B;] = { password };\r\n CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);\r\n CFArrayRef p12Items;\r\n\r\nOSStatus result = SecPKCS12Import((__bridge CFDataRef)p12Data, optionsDictionary, &amp;p12Items);\r\n\r\nif(result == noErr) {\r\n CFDictionaryRef identityDict = CFArrayGetValueAtIndex(p12Items, 0);\r\n SecIdentityRef identityApp =(SecIdentityRef)CFDictionaryGetValue(identityDict,kSecImportItemIdentity);\r\n\r\nSecCertificateRef certRef;\r\n SecIdentityCopyCertificate(identityApp, &amp;certRef);\r\n\r\nSecCertificateRef certArray&#x5B;1] = { certRef };\r\n CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL);\r\n CFRelease(certRef);\r\n\r\nNSURLCredential *credential = &#x5B;NSURLCredential credentialWithIdentity:identityApp certificates:(__bridge NSArray *)myCerts persistence:NSURLCredentialPersistencePermanent];\r\n CFRelease(myCerts);\r\n\r\n&#x5B;&#x5B;challenge sender] useCredential:credential forAuthenticationChallenge:challenge];\r\n }\r\n else {\r\n \/\/ Certificate is invalid or password is invalid given the certificate\r\n NSLog(@&quot;Invalid certificate or password&quot;);\r\n return;\r\n }\r\n } else {\r\n \/\/ For normal authentication based on username and password. This could be NTLM or Default.\r\n if (&#x5B;&#x5B;challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {\r\n NSLog(@&quot;Certificate might be required&quot;);\r\n }\r\n NSURLCredential *credential = &#x5B;NSURLCredential credentialWithUser:self.account.username\r\n password:self.account.password\r\n persistence:NSURLCredentialPersistenceNone];\r\n &#x5B;&#x5B;challenge sender] useCredential:credential forAuthenticationChallenge:challenge];\r\n }\r\n\r\n}\r\n\r\n<\/pre>\n<p>Wszystko wygl\u0105da dobrze na pierwszy rzut oka. W wi\u0119kszo\u015b\u009bci przypadk\u00f3w\u00a0nawet b\u0119dzie\u0082 dzia\u0142a\u0142o. Je\u017celi jednak trafisz na problem ze swoim serwerem i sprawdzisz jak to wygl\u0105da w Wiresharku:<\/p>\n<p><a href=\"http:\/\/oso.com.pl\/wp-content\/uploads\/2013\/05\/ios_certs.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"217\" data-permalink=\"https:\/\/oso.com.pl\/?attachment_id=217\" data-orig-file=\"https:\/\/oso.com.pl\/wp-content\/uploads\/2013\/05\/ios_certs.png\" data-orig-size=\"1549,754\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"iOS certs\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/oso.com.pl\/wp-content\/uploads\/2013\/05\/ios_certs-1024x498.png\" class=\"wp-image-217 alignnone\" src=\"http:\/\/oso.com.pl\/wp-content\/uploads\/2013\/05\/ios_certs.png\" alt=\"iOS certs\" width=\"1084\" height=\"528\" srcset=\"https:\/\/oso.com.pl\/wp-content\/uploads\/2013\/05\/ios_certs.png 1549w, https:\/\/oso.com.pl\/wp-content\/uploads\/2013\/05\/ios_certs-300x146.png 300w, https:\/\/oso.com.pl\/wp-content\/uploads\/2013\/05\/ios_certs-1024x498.png 1024w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/a><\/p>\n<p>Widzimy, \u017ce co\u015b\u009b nie jest do ko\u0144ca w porz\u0105dku. Klient wys\u0142a\u0142\u0082 ten sam certyfikat dwa razy. Og\u00f3lnie nie powinno by\u0107 to problemem, ale je\u017celi\u00a0Tw\u00f3j serwer przetwarza certyfikaty i spodziewa si\u0119\u0099, \u017ce\u0099 b\u0119d\u0105\u0085 uporz\u0105dkowane w \u0142a\u0144cuch: certyfikat klienta, wydawca certyfikatu klienta itd. &#8211; wtedy mog\u0105\u0085 by\u0107 problemy.<\/p>\n<p>Problem tego typu mo\u017cna\u0085 rozwi\u0105za\u0107 po stronie klienta lub po stronie serwera. Jednak najpoprawniejsze wydaje mi si\u0119\u0099 naprawienie go po stronie klienta. Zgodnie z\u00a0<a href=\"http:\/\/www.ietf.org\/rfc\/rfc2246.txt\" target=\"_blank\">RFC2246<\/a> i <a href=\"http:\/\/tools.ietf.org\/html\/rfc5246\" target=\"_blank\">RFC5246<\/a>\u00a0certyfikat klienta powinien wyst\u0105pi\u0107\u0087 tylko raz:<\/p>\n<p><em id=\"__mceDel\">certificate_list<br \/>\nThis is a sequence (chain) of X.509v3 certificates. The sender&#8217;s<br \/>\ncertificate must come first in the list. Each following<br \/>\ncertificate must directly certify the one preceding it. Because<br \/>\ncertificate validation requires that root keys be distributed<br \/>\nindependently, the self-signed certificate which specifies the<br \/>\nroot certificate authority may optionally be omitted from the<br \/>\nchain, under the assumption that the remote end must already<br \/>\npossess it in order to validate it in any case.<br \/>\nThe same message type and structure will be used for the client&#8217;s<br \/>\nresponse to a certificate request message. Note that a client may<br \/>\nsend no certificates if it does not have an appropriate certificate<br \/>\nto send in response to the server&#8217;s authentication request.<\/em><\/p>\n<p>Na szcz\u00c4\u0099\u0139\u009bcie poprawienie tego problemu jest trywialne. Zamieniamy t\u00c4\u0099 linijk\u00c4\u0099:<\/p>\n<p>NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identityApp <strong>certificates:(__bridge NSArray *)myCerts<\/strong> persistence:NSURLCredentialPersistencePermanent];<\/p>\n<p>na:<\/p>\n<p>NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identityApp <strong>certificates:nil<\/strong> persistence:NSURLCredentialPersistencePermanent];<\/p>\n<p>Testujemy, wszystko wygl\u0105da poprawnie. Problem rozwi\u0105\u0085zany bez kosztownych zmian w kodzie serwera.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Kolejny o certyfikatach. Powiedzmy, \u017ce piszesz aplikacj\u0119\u0099 na iOS, kt\u00f3ra ma uwierzytelnia\u0107\u0087 si\u0119 za pomoc\u0105 certyfikatu. Implementujesz co\u015b\u009b takiego: &#8211; (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { if (&#x5B;challenge previousFailureCount] &gt; 0) { NSLog(@&quot;Incorrect auth challenge %@&quot;, challenge); &#x5B;&#x5B;challenge sender] cancelAuthenticationChallenge:challenge]; return; } \/\/ Checking the server certificate if (&#x5B;&#x5B;challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate &amp;&amp; self.account.clientCertificate.privateRepresentation.length &gt; &hellip; <a href=\"https:\/\/oso.com.pl\/?p=226\" class=\"more-link\">Czytaj dalej<span class=\"screen-reader-text\"> \u201eBli\u017aniacze certyfikaty z iOS\u201d<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[11],"tags":[],"class_list":["post-226","post","type-post","status-publish","format-standard","hentry","category-mdm"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p217OK-3E","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/oso.com.pl\/index.php?rest_route=\/wp\/v2\/posts\/226","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/oso.com.pl\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/oso.com.pl\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/oso.com.pl\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/oso.com.pl\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=226"}],"version-history":[{"count":3,"href":"https:\/\/oso.com.pl\/index.php?rest_route=\/wp\/v2\/posts\/226\/revisions"}],"predecessor-version":[{"id":294,"href":"https:\/\/oso.com.pl\/index.php?rest_route=\/wp\/v2\/posts\/226\/revisions\/294"}],"wp:attachment":[{"href":"https:\/\/oso.com.pl\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=226"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oso.com.pl\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=226"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oso.com.pl\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=226"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}