I have developed an app that connects to different pages and allows validation using a digital certificate. In most of the webs I can access without problem, but when I try to connect to the url: https://www.sedecatastro.***.es/Accesos/SECAccTitular.aspx?Dest=24, I always get the error: Error Domain = NSURLErrorDomain Code = -1206 The server “xxxx” requires a client certificate. I do not understand the error because I am doing the validation in other websites correctly and even in other sections of this same website.
class SessionDelegate:NSObject, URLSessionDelegate
{
let certificadosName: [String] = ["AC_Administracion_Publica","ac_raiz_fnmt","Camerfirma_AAPP_II_Chambers_of_Commerce_Root","Camerfirma_Corporate_Server_II_Chambers_of_Commerce_Root","Chambers_of_Commerce_Root","claveRaiz","DigiCert_High_Assurance_EV_Root_CA","Entrust_Root_Certification_Authority_G","GeoTrust_SSL_CA_G_GeoTrust_Global_CA","Izenpe_com"
,"GlobalSign", "GlobalSign_Extended_Validation", "USERTrust_RSA", "SEDE_CATASTRO"]
let certFileType = "cer"
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
&& challenge.protectionSpace.serverTrust != nil
{
let trust = challenge.protectionSpace.serverTrust
var certs: [SecCertificate] = [SecCertificate]()
for certificadoName in certificadosName
{
let pem = Bundle.main.url(forResource: certificadoName, withExtension: certFileType)
if (pem != nil)
{
let data = NSData(contentsOf: pem!)
let cert = SecCertificateCreateWithData(nil, data!)
certs.append(cert!)
}
}
SecTrustSetAnchorCertificates(trust!, certs as CFArray)
var result=SecTrustResultType.invalid
if SecTrustEvaluate(trust!,&result)==errSecSuccess {
if result==SecTrustResultType.proceed || result==SecTrustResultType.unspecified {
let proposedCredential = URLCredential(trust: trust!)
completionHandler(.useCredential,proposedCredential)
return
}
}
completionHandler(.performDefaultHandling, nil)
}
else if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate)
{
sendClientCertificate(for: challenge, via: completionHandler)
}
else
{
completionHandler(.performDefaultHandling, nil)
}
}
func sendClientCertificate(for challenge: URLAuthenticationChallenge, via completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let certificado: String? = Tramite.selectedCertificado
let password: String? = Tramite.passwordCertificado
if(certificado != nil && password != nil )
{
guard let data = try? Data(contentsOf: URL(fileURLWithPath: certificado!)),
let credential = credential(from: data, withPassword: password ?? "") else {
challenge.sender?.cancel(challenge)
return completionHandler(.rejectProtectionSpace, .none)
}
return completionHandler(.useCredential, credential);
}
else{
return completionHandler(.rejectProtectionSpace, .none)
}
}
func credential(from data: Data, withPassword password: String) -> URLCredential? {
guard let security = security(from: data, withPassword: password) else {
return .none
}
return URLCredential(
identity: security.identity,
certificates: security.certificates,
persistence: .forSession
)
}
func security(from data: Data, withPassword password: String) -> (identity: SecIdentity, trust: SecTrust, certificates: [SecCertificate])? {
var _items: CFArray?
let securityError = SecPKCS12Import(data as NSData,
[ kSecImportExportPassphrase as String : password ] as CFDictionary,
&_items);
guard let items = _items as? [Any],
let dict = items.first as? [String:Any],
securityError == errSecSuccess else {
return .none
}
let identity = dict["identity"] as! SecIdentity
let trust = dict["trust"] as! SecTrust;
// Certificate chain
var certificate: SecCertificate!
SecIdentityCopyCertificate(identity, &certificate);
return (identity, trust, [certificate]);
}
}
Post
Replies
Boosts
Views
Activity
I have developed an app that allows the user to validate himself on a website and, through a webview, navigate through it. In the event that the user tries to download a document through a link, it is stored on their device. The problem arises when the download url is of the type blob: // https: // ....
To contemplate this case, I have tried to evaluate a javascript that allows obtaining the bytes of the document in base64 using the XMLHttpRequest object (analogously to how I have solved it in android), but in this case the onload method always the value 0 for the status attribute of the XMLHttpRequest object. Is there a solution to be able to download blob files from a WKWebView in swift?
Code
I have an app that uses an SQLite database to store some information.
In the first installation of the app I create the database and pass a script to include the necessary data in it. Among these data I have a master of administrative regions of Spain, which implies a slow initialization process. What are the best practices to carry out this initial load?
I've tried throwing it in a background thread, but if I do, I get an EXC_BAD_ACCESS error.
I am working on an application on IOS and I need to be able to decrypt an element that has been encrypted with a public key, but I only know the modulus and the private exponent of the private key. How can I obtain the private key from these elements in IOS?
In java, with the following code I can get the private key from these elements and I can decrypt the element.
final RSAPrivateKeySpec privateSpec = new RSAPrivateKeySpec(MODULUS, PRIVATE_EXPONENT);
final KeyFactory factory = KeyFactory.getInstance("RSA");
final PrivateKey priv = factory.generatePrivate(privateSpec);
On ios, I got the following code, but it doesn't return the private key:
let smodulus = "00c35d6ac32d287dab681c78272931b60ca442bd4505e1b306432af92ef6e07bc3e4e24c2bc2dac69c94753390c3793b80734ef906520a96cafb146ce587ab383e78efc58c5ccf56b5084f3f9bc719e646a0361155ab56b7d71b49f1f90673383ea0fdb4a67900c0973930aa3bc7071c479b4a5d229fcab7ce22b84c1637d7e70b"
let sPrivateExponent = "1f2535700832fc55e73322b49b8ca14942a6a125efda1b805414f5c4d6f6d2c45828fb9bbe64c2651405db42a8e71ae54f7cb7969a5db5cc865aab41ac6f4f77deccb51496fe588f9dcd724a1d49cab96712621afc9c656c56dea011f8ab8e12a321fd62430902b15586a36093a6679e31b67017397da83b0992f5f816017701"
let sPublicExponent = "010001"
public static func getPrivateKey(smodulus: String, sPrivateExponent: String) -> SecKey? {
let pubExponent: [UInt8] = [1, 0, 1]
let exponent: [UInt8] = sPrivateExponent.hexaBytes
var modulus: [UInt8] = smodulus.hexaBytes
//modulus.insert(0x00, at: 0)
var modulusEncoded: [UInt8] = []
modulusEncoded.append(0x02)
modulusEncoded.append(contentsOf: lengthField(of: modulus))
modulusEncoded.append(contentsOf: modulus)
var exponentEncoded: [UInt8] = []
exponentEncoded.append(0x02)
exponentEncoded.append(contentsOf: lengthField(of: exponent))
exponentEncoded.append(contentsOf: exponent)
var sequenceEncoded: [UInt8] = []
sequenceEncoded.append(0x30)
sequenceEncoded.append(contentsOf: lengthField(of: (modulusEncoded + exponentEncoded)))
sequenceEncoded.append(contentsOf: (modulusEncoded + exponentEncoded))
let keyData = Data(bytes: sequenceEncoded)
// RSA key size is the number of bits of the modulus.
let keySize = (modulus.count * 8)
let attributes: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeyClass as String: kSecAttrKeyClassPrivate,
kSecAttrKeySizeInBits as String: keySize
]
let privateKey = SecKeyCreateWithData(keyData as CFData, attributes as CFDictionary, nil)
return privateKey
}
private static func lengthField(of valueField: [UInt8]) -> [UInt8] {
var count = valueField.count
if count < 128 {
return [ UInt8(count) ]
}
// The number of bytes needed to encode count.
let lengthBytesCount = Int((log2(Double(count)) / 8) + 1)
// The first byte in the length field encoding the number of remaining bytes.
let firstLengthFieldByte = UInt8(128 + lengthBytesCount)
var lengthField: [UInt8] = []
for _ in 0..<lengthBytesCount {
// Take the last 8 bits of count.
let lengthByte = UInt8(count & 0xff)
// Add them to the length field.
lengthField.insert(lengthByte, at: 0)
// Delete the last 8 bits of count.
count = count >> 8
}
// Include the first byte.
lengthField.insert(firstLengthFieldByte, at: 0)
return lengthField
}
extension StringProtocol {
var hexaData: Data { .init(hexa) }
var hexaBytes: [UInt8] { .init(hexa) }
private var hexa: UnfoldSequence<UInt8, Index> {
sequence(state: startIndex) { startIndex in
guard startIndex < self.endIndex else { return nil }
let endIndex = self.index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
defer { startIndex = endIndex }
return UInt8(self[startIndex..<endIndex], radix: 16)
}
}
}
I am working on a project that allows access to certificates from a cryptographic card that supports communication via NFC with the mobile device.
At this point, I am able to read the data from the card (public certificate and root certificate) and am able to send data (a hash) to the card and have it sign it with the private certificate.
On the other hand, with the following code I can validate a user while browsing using a webview when the server needs authentication with a digital certificate.
func sendClientCertificate(for challenge: URLAuthenticationChallenge, via completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard let data = try? Data(contentsOf: URL(fileURLWithPath: certificado!)),
let credential = credential(from: data, withPassword: password ?? "") else {
challenge.sender?.cancel(challenge)
return completionHandler(.rejectProtectionSpace, .none)
}
return completionHandler(.useCredential, credential);
}
func credential(from data: Data, withPassword password: String) -> URLCredential? {
guard let security = security(from: data, withPassword: password) else {
return .none
}
return URLCredential(
identity: security.identity,
certificates: security.certificates,
persistence: .permanent
)
}
func security(from data: Data, withPassword password: String) -> (identity: SecIdentity, trust: SecTrust, certificates: [SecCertificate])? {
var _items: CFArray?
let securityError = SecPKCS12Import(data as NSData,
[ kSecImportExportPassphrase as String : password ] as CFDictionary,
&_items);
guard let items = _items as? [Any],
let dict = items.first as? [String:Any],
securityError == errSecSuccess else {
return .none
}
let identity = dict["identity"] as! SecIdentity
let trust = dict["trust"] as! SecTrust;
// Certificate chain
var certificate: SecCertificate!
SecIdentityCopyCertificate(identity, &certificate);
return (identity, trust, [certificate]);
}
What classes should I delegate to be able to control the communication at a low level and be able to send the data that the server needs to sign to the card?
I have created an app that allows access to a url using URLSession and it is working correctly when I launch the app using XCode, but it does not work when I submit the app for testing in testfligh. It seems that something is blocking requests made from URLSession. Is it possible that there is some configuration that you are not taking into account for publishing to testflight
I am using the CryptoTokenKit functionality to be able to perform validations on web pages that use digital certificates to ensure the user's identity, using the digital certificates included in the Spanish national electronic identity document.
I manage to use it correctly in most cases, but sometimes I get an error when trying to retrieve the previously created token. This error is fixed by restarting the phone.
I had create the Feedback Assistant with number FB14095789.