RSA key for web client authentication

Hi all, Nice to meet you, this is my first post! In the past, i developed an OpenSSL engine in order to use my custom crypto token for RSA signatures. I used such engine in Linux Qt WebView widget (based on Webkit) in order to authenticate to HTTPS using client certificate and private key contained into the token. I'd like to do the same in iOS, is it possible with WKWebView? Or with some keychain API? Thanks P

Replies

is it possible with WKWebView?

Not on iOS. On macOS you can publish your crypto token via the CryptoTokenKit and it will be used by all system services including

WKWebView
and the Safari app. iOS does not support this, alas. Your only option right now is use
UIWebView
. This lets you intercept the underlying HTTPS requests, allowing you to run those requests with your own TLS. This is not fun.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi Thank you very much for the answer. Do you have a sample code or just a snippet ? F

Do you have a sample code … ?

My previous post had a link to the CustomHTTPProtocol sample code.

IMPORTANT This sample demonstrates intercepting

NSURLAuthenticationMethodServerTrust
authentication challenges, which is a bit pointless these days because the support in
WKWebView
for those challenges works just fine. However, it should be relatively straightforward to adapt it to intercept
NSURLAuthenticationMethodClientCertificate
authentication challenges.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I apologize,

I saw the code and i didn't understant how to modify it for my purpose.

When you wrote i have to use my own TLS, you mean that i have to manage all the handshake and encryption and decryption with the agreed chipersuite ?

Thanks.

P

I saw the code and i didn't understant how to modify it for my purpose.

OK. I believe I’ve confused you here, and I apologise for that. Earlier I wrote:

However, it should be relatively straightforward to adapt it to intercept

NSURLAuthenticationMethodClientCertificate
authentication challenges.

which is true but irrelevant to your requirements. The custom

NSURLProtocol
technique will let you see all the requests made by the
UIWebView
. A lot of developers just want to handle client identity authentication challenges using the built-in networking stack, and the technique shown by CustomHTTPProtocol can be readily adapted for that. However, that’s not possible in your case.

The sticking point is that the TLS in the built-in networking stack uses the built-in security stack for its crypto operations. There’s no ability for you to plug your hardware token in to this stack (on iOS; on macOS you can do this using CryptoTokenKit). Thus, not only do you need to implement the crypto primitives, you need to implement:

  • TLS on top of that

  • HTTP on top of that

This, as I said earlier, is not fun.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

First of all, thank you for your support, I finally came to a custom NSURLProtocol solution to handle my needs. Now I have to switch to WKWebview due to Apple restriction on apps update from December 2020.
I sadly didn't find anything similar to a custom protocol in WKWebview, there is only the WKURLSchemeHandler but it doesn't allow to handle http or https in a custom way. Is there another way or other objects to use with WKWebview that allow me to switch from UIWebview to WKWebview and (possibly) reuse my custom NSURLProtocol?

Is there another way or other objects to use with

WKWebview
that allow me to switch from
UIWebview
to
WKWebview
and (possibly) reuse my custom
NSURLProtocol
?

Sadly, the ability to intercept all the network traffic generated by the web view is one of the missing pieces in

WKWebView
right now.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

And what about CryptoTokenKit? By documentation it seems possible to use it on ios 13.0+
In one of your previous replies Re: RSA key for web client authentication you said that maybe is possible to use CryptoTokenKit and WKWebView to achieve in our goal. Is now possible on iOS as it seems?

And what about CryptoTokenKit?

I’d expect this to work just fine on macOS. I discussed this issue with DTS’s CryptoTokenKit specialist just last week and my understanding, based on that conversation, is that third-party CryptoTokenKit extensions are not currently supported on iOS.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
You can now create a Persistent Token extension on iOS 14 and implement the TKTokenDriver, TKToken and TKTokenSession objects you need. You put the extension in your app and it will get loaded even if your app has not launched. Apple's own apps will use your extension bu the UI is clumsy. A WKWebView in your own app will use your token, but not automatically. First, you need to add com.apple.token to your entitlements:
Code Block <key>keychain-access-groups</key>
<array>
<string>com.apple.token</string>
</array>
You need to have your delegate handle
Code Block
webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
and when you get challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate you should query for SecIdentities to use:
Code Block  
var keychainItems = [[String:AnyObject]]()
for tokenID in TKTokenWatcher().tokenIDs {
            let query : [String:Any] = [kSecClass as String:kSecClassIdentity,
                                        kSecAttrTokenID as String: tokenID,
                                        kSecReturnAttributes as String: true,
                                        kSecReturnRef as String: true,
                                        kSecMatchLimit as String: kSecMatchLimitAll]
            
            var items : CFTypeRef?
            status = SecItemCopyMatching(query as CFDictionary, &items)
            if status == errSecSuccess && items != nil {
                statusOKs += 1
                if let found = items as? [[String:AnyObject]] {
                    for item in found {
                        keychainItems.append(item)
                    }
                }
            }
        }


If you have multiple identities, you should display a list for the user to choose from.
Finally make a credential:        
Code Block
let cred = URLCredential(identity: identity, certificates: nil, persistence: .forSession)
and return it through the callback handler from the call to your web view delegate.