在网络服务器iOS应用上安装TLS证书

时间:2018-12-21 13:02:55

标签: swift swish

我正在尝试将Swish付款集成到我开发的应用程序之一中。 为了能够连接到swish api,我必须根据该文档“从Swish证书管理中设置TLS证书并将其安装在“我的”网络服务器上”。以下是完整的技术文档https://developer.getswish.se/merchants-api-manual/4-merchant-setup-process/

我不明白的问题是我不使用Web服务器,也无法在其中安装那些证书。

我的应用程序仅为客户提供一些服务,在按下“付款”按钮后,应打开Swish应用程序以简短地完成交易。

我想做的是发布请求以获取请求令牌,通过该令牌我可以打开装有付款明细的swish应用程序。 我确定问题出在证书上,但是找不到解释如何导入(集成)证书的好资料。

let strURL =“ https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests/

guard let postURL = URL(string:strURL)else {             打印(“无法创建网址”)             返回         }

    var request = URLRequest(url: postURL)

    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue("application/json", forHTTPHeaderField: "Accept")

    let data: [String: Any] = [
        "callbackUrl": "https://example.com/api/swishcb/paymentrequests",
        "payeeAlias": "123xxxxxxx", // The Swish number of the payee. It needs to match with Merchant Swish number.
        "amount": "100",
        "currency": "SEK",
        "message": "Test request to get the token"
    ]

    do {
        let jsonParams = try JSONSerialization.data(withJSONObject: data, options: [])
        request.httpBody = jsonParams
    } catch {
        print("Error serializing the parameters of the post request")
        return
    }

    // response will contain a Token, unique for each payment request

    let config = URLSessionConfiguration.default
    config.timeoutIntervalForResource = 120
    config.timeoutIntervalForRequest = 120
    let session = URLSession(configuration: config) 

    session.dataTask(with: request) { (data, response, error) in
        print("Data \(data)")
        print("Response \(response)")
        if error != nil {
            print("Error post request \(error?.localizedDescription)")
        }
    }.resume()

我得到的错误是:  错误发布请求可选(“发生SSL错误,无法建立与服务器的安全连接。”)

018-12-21 12:24:55.549759 + 0200 tolk-24-7 [7230:111102] [BoringSSL] boringssl_context_alert_callback_handler(3718)[C6.1:2] [0x7fce4a77bf00]警报级别:致命,描述:握手失败 2018-12-21 12:24:55.550047 + 0200 tolk-24-7 [7230:111102] [BoringSSL] boringssl_session_errorlog(224)[C6.1:2] [0x7fce4a77bf00] [boringssl_session_handshake_incomplete] SSL_ERROR_SSL(1):内部操作失败图书馆 2018-12-21 12:24:55.550332 + 0200 tolk-24-7 [7230:111102] [BoringSSL] boringssl_session_handshake_error_print(205)[C6.1:2] [0x7fce4a77bf00] 140523985879704:错误:10000410:SSL例程:OPENSSL_internal: SSLV3_ALERT_HANDSHAKE_FAILURE:/BuildRoot/Library/Caches/com.apple.xbs/Sources/boringssl_Sim/boringssl-109.220.4/ssl/tls_record.cc:586:SSL警报编号40 2018-12-21 12:24:55.550585 + 0200 tolk-24-7 [7230:111102] [BoringSSL] boringssl_context_get_error_code(3539)[C6.1:2] [0x7fce4a77bf00] SSL_AD_HANDSHAKE_FAILURE 2018-12-21 12:24:55.552299 + 0200 tolk-24-7 [7230:111102] TI​​C TCP连接失败[6:0x600002dd6c40]:3:-9824 Err(-9824) 2018-12-21 12:24:55.555924 + 0200 tolk-24-7 [7230:111102] NSURLSession / NSURLConnection HTTP加载失败(kCFStreamErrorDomainSSL,-9824) 2018-12-21 12:24:55.556052 + 0200 tolk-24-7 [7230:111102]任务<7888D080-D175-4DBF-8F66-4183F0D653E6>。<1> HTTP加载失败(错误代码:-1200 [3: -9824]) 2018-12-21 12:24:55.556234 + 0200 tolk-24-7 [7230:111613]任务<7888D080-D175-4DBF-8F66-4183F0D653E6>。<1>已完成,错误-代码:-1200

1 个答案:

答案 0 :(得分:1)

我感到您很沮丧,我本身还没有使用Swish API,但是好像URLSession无法执行客户端证书请求。在该步骤上握手失败。

有一个向URLSession添加URLSessionDelegate的选项,以处理诸如ServerTrust和ClientCertificate之类的身份验证挑战。他们在这里讨论: Swift 3 UrlSession with client authentication by certificate

如果能够使用客户端证书和私钥创建p12 / pfx,则可以使用SecPKCS12Import导入它,并将其用于URLSessionDelegate中收到的NSURLAuthenticationMethodClientCertificate中的URLCredential信任。这是我写的一个实现:

func urlSession(
        _ session: URLSession,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
    {

        let authenticationMethod = challenge.protectionSpace.authenticationMethod
        if authenticationMethod == NSURLAuthenticationMethodServerTrust {
            //Handle server trust if necessary
        } else if authenticationMethod == NSURLAuthenticationMethodClientCertificate {
            if let clientCredential = try? getClientUrlCredential() {
                completionHandler(.useCredential, clientCredential)
            } else {
                completionHandler(.cancelAuthenticationChallenge, nil)
            }
        }
    }

getClientUrlCredential函数:

private func getClientUrlCredential() throws -> URLCredential {

        let p12Data = getP12Data() //Get the data from the bundle if it's bundled in the app
        let p12Key = getP12Key() //you need the key set for creating the p12/pfx

        let certOptions: NSDictionary = [
            kSecImportExportPassphrase as NSString : p12Key as NSString
        ]

        // import certificate to read its entries
        var items: CFArray?
        let status = SecPKCS12Import(p12Data, certOptions, &items)

        if status == errSecSuccess,
            let items = items,
            let dict = (items as Array).first as? [String: AnyObject],
            let certChain = dict[kSecImportItemCertChain as String] as? [SecTrust] {

            // Check if SecIdentityGetTypeID is present
            guard let cfIdentity = dict[kSecImportItemIdentity as String] as CFTypeRef?,
                CFGetTypeID(cfIdentity) == SecIdentityGetTypeID() else {
                    throw URLSessionPinningDelegateError.localClientCertificateError
            }

            let identity = dict[kSecImportItemIdentity as String] as! SecIdentity
            return URLCredential(
                identity: identity,
                certificates: certChain,
                persistence: .forSession
            )
        }

        //Failed to read local certificate, throw error
        throw URLSessionPinningDelegateError.localClientCertificateError
    }

使用有效的客户端证书,您应该能够履行客户端问候并为服务器设置TLS,因为这似乎是您当前失败的地方。您通过BoringSSL获得的SSL警报编号40至少对我来说是建议。

希望这至少会为您指明正确的方向,并乐意在需要时提供进一步的支持。