SecTrustPolicy fail with self-signed cert - ssl

So I created this test case (a mish mash of existing alamofire test cases):
func testHTTPBasicAuthenticationWithValidCredentialsSelfSignedSuccess() {
// Given
let expectation = expectationWithDescription("\(URLString) 200")
var request: NSURLRequest?
var response: NSHTTPURLResponse?
var data: NSData?
var error: NSError?
setRootCertificateAsLoneAnchorCertificateForTrust(serverTrust)
let policies = [SecPolicyCreateBasicX509()]
SecTrustSetPolicies(serverTrust, policies)
// When
Alamofire.request(.GET, URLString)
.authenticate(user: user, password: password)
.response { responseRequest, responseResponse, responseData, responseError in
request = responseRequest
response = responseResponse
data = responseData
error = responseError
expectation.fulfill()
}
waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
// Then
XCTAssertNotNil(request, "request should not be nil")
XCTAssertNotNil(response, "response should not be nil")
XCTAssertTrue(data?.length > 0, "Data not found.")
XCTAssertNil(error, "error should be nil")
}
The Root CA is a self-signed cert for an existing sight that works.
But I get this error back:
Test Suite 'Selected tests' started at 2015-08-12 12:46:37.512 Test
Suite 'StageAuthentication' started at 2015-08-12 12:46:37.514 Test
Case '-[Alamofire_iOS_Tests.StageAuthentication
testHTTPBasicAuthenticationWithValidCredentialsSelfSignedSuccess]'
started. 2015-08-12 12:46:37.663 xctest[3641:12220875]
NSURLSession/NSURLConnection HTTP load failed
(kCFStreamErrorDomainSSL, -9813)
/Users/wynne_b/Alamofire/Tests/QuestAuthentication.swift:309: error:
-[Alamofire_iOS_Tests.StageAuthentication testHTTPBasicAuthenticationWithValidCredentialsSelfSignedSuccess] :
XCTAssertNotNil failed - response should not be nil
/Users/wynne_b/Alamofire/Tests/QuestAuthentication.swift:310: error:
-[Alamofire_iOS_Tests.StageAuthentication testHTTPBasicAuthenticationWithValidCredentialsSelfSignedSuccess] :
XCTAssertTrue failed - Data not found.
/Users/wynne_b/Alamofire/Tests/QuestAuthentication.swift:311: error:
-[Alamofire_iOS_Tests.StageAuthentication testHTTPBasicAuthenticationWithValidCredentialsSelfSignedSuccess] :
XCTAssertNil failed: "Error Domain=NSURLErrorDomain Code=-1202 "The
certificate for this server is invalid. You might be connecting to a
server that is pretending to be “portal.care180.com” which could put
your confidential information at risk."
UserInfo={NSLocalizedDescription=The certificate for this server is
invalid. You might be connecting to a server that is pretending to be
“portal.care180.com” which could put your confidential information at
risk., NSLocalizedRecoverySuggestion=Would you like to connect to the
server anyway?, _kCFStreamErrorDomainKey=3,
NSUnderlyingError=0x7ae21c60 {Error Domain=kCFErrorDomainCFNetwork
Code=-1202 "(null)"
UserInfo={_kCFStreamPropertySSLClientCertificateState=0,
_kCFNetworkCFStreamSSLErrorOriginalValue=-9813, _kCFStreamErrorCodeKey=-9813, _kCFStreamErrorDomainKey=3, kCFStreamPropertySSLPeerTrust=,
kCFStreamPropertySSLPeerCertificates={type = immutable, count = 1, values = ( 0 :
)}}}, _kCFStreamErrorCodeKey=-9813,
NSErrorFailingURLStringKey=https://portal.care180.com/services/init.json,
NSErrorPeerCertificateChainKey={type =
immutable, count = 1, values = ( 0 : )},
NSErrorClientCertificateStateKey=0,
NSURLErrorFailingURLPeerTrustErrorKey=,
NSErrorFailingURLKey=https://portal.care180.com/services/init.json}" -
error should be nil Test Case
'-[Alamofire_iOS_Tests.StageAuthentication
testHTTPBasicAuthenticationWithValidCredentialsSelfSignedSuccess]'
failed (0.156 seconds). Test Suite 'StageAuthentication' failed at
2015-08-12 12:46:37.671. Executed 1 test, with 3 failures (0
unexpected) in 0.156 (0.157) seconds Test Suite 'Selected tests'
failed at 2015-08-12 12:46:37.672. Executed 1 test, with 3 failures
(0 unexpected) in 0.156 (0.160) seconds Program ended with exit code:
1
Sorry for being dense: what am I doing wrong? Or is there an Alamofire test that does this with a different cert and host?

I confused the root and the leaf. My bad.

Related

Domain=NSURLErrorDomain Code=-1005 "The network connection was lost in swift5

I am using swift5 & Xcode Version 13.0 (13A233). I am using cocapod
pod 'Alamofire' , '~> 4.9.1'
I just connect using IP, it is working fine.But when I connect to domain like https://www.example.net it shows
Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={_kCFStreamErrorCodeKey=-4, NSUnderlyingError=0x600002af2b50 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" UserInfo={NSErrorPeerAddressKey=<CFData 0x6000007c8230 [0x1056ddaf0]>{length = 16, capacity = 16, bytes = 0x100201bb772858170000000000000000}, _kCFStreamErrorCodeKey=-4, _kCFStreamErrorDomainKey=4}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <A49E8D5B-1DE3-487C-B4F7-50376AF188AE>.<3>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <A49E8D5B-1DE3-487C-B4F7-50376AF188AE>.<3>"
), NSLocalizedDescription=The network connection was lost., NSErrorFailingURLStringKey=https://www.example.net/api/second-api, NSErrorFailingURLKey=https://www.example.net/api/second-api, _kCFStreamErrorDomainKey=4}
I have also add App Transport Security Settings like bellow & here is the image
Here is the code I have used..
API One:
func firstApi() {
Alamofire.request("https://www.example.net/api/first-api", method: .post, parameters: [
"param1":"",
"param2":"",
],headers: headers).responseJSON{ [self](responseData) -> Void in
secondApi()
}
}
API Two:
func secondApi() {
Alamofire.request("https://www.example.net/api/second-api", method: .post, parameters: [
"param1":"",
"param2":"",
"param3":"",
],headers: headers).responseJSON{ [self](responseData) -> Void in
}
}
In the above code, I have called Second API from first API. First API is responding nicely. But in second API which I call from first API response shows above error..
But Only single API called but when I call another API from single API shows error
I don't know what is reason. Please help me to solve the problem..

Cannot connect to host www.reddit.com:443 ssl:True

I wanted to use aiohttp.request in order to get Reddit post, but when I ran the code it gives me this error, any possible solution?
Code:
#command(name='meme')
#guild_only()
async def meme_cmd(self, ctx):
async with request("GET", "https://www.reddit.com/r/meme/", headers={}) as response:
data = await response.json()
print(data)
Error:
Command raised an exception: ClientConnectorCertificateError: Cannot connect to host www.reddit.com:443 ssl:True [SSLCertVerificationError: (1, "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname m
ismatch, certificate is not valid for 'www.reddit.com'. (_ssl.c:1123)")]

SSL_error_SSL error on tls_read

In a production setup, randomly a opensips error comes up indicating tls_read failed due to SSL_error_SSL error.
Opensips fails the tls/tcp session and a new session is created and it works fine.
Please provide any pointers on why tls_read would fail with ssl_error_ssl return code.
Opensips code invokes,
ssl = c->extra_data;
ret = SSL_read(ssl, buf, len);
if (ret >0)
{
}
else
{
err = SSL_get_error(ssl, ret);
switch (err) {
case SSL_ERROR_ZERO_RETURN:
LM_INFO("TLS connection to %s:%d closed cleanly\n",
ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
/*
* mark end of file
*/
c->state = S_CONN_EOF;
return 0;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
return 0;
case SSL_ERROR_SYSCALL:
LM_ERR("SYSCALL error -> (%d) <%s>\n",errno,strerror(errno));
default:
LM_ERR("TLS connection to %s:%d read failed\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
LM_ERR("TLS read error: %d\n",err);
c->state = S_CONN_BAD;
tls_print_errstack();
return -1;
}
I want to highlight that TLS connection was established fine and a message is successfully received and send. When the second message is received and SSL_read is invoked there is below error,
2018-05-11T11:23:16.000-04:00 [local2] [err] ffd-alpha-zone1-ccm1.ipc.com /usr/sbin/opensipsInternal[10325]: ERROR:core:_tls_read: TLS connection to 10.204.34.62:51519 read failed
2018-05-11T11:23:16.000-04:00 [local2] [err] ffd-alpha-zone1-ccm1.ipc.com /usr/sbin/opensipsInternal[10325]: ERROR:core:_tls_read: TLS read error: 1
2018-05-11T11:23:16.000-04:00 [local2] [err] ffd-alpha-zone1-ccm1.ipc.com /usr/sbin/opensipsInternal[10325]: ERROR:core:tls_print_errstack: TLS errstack: error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned
In the pcap, there is re-transmission of every tls packet both sides and when this packet is read, there seems the packet is the second portion of fragemented packet.
Thanks,

youtubeAPI v3 invalid certificate on tvOS

I want to request the youtube-data-api v3 from my tvOS App. To do so I wrote the following class:
class YoutubeSearch {
static let sharedClient = YoutubeSearch()
private var task: NSURLSessionDataTask!
func getVideoNSURLsForTitle(title: String, completionHandler: ([String], NSError?) -> Void ) -> NSURLSessionTask {
// URL
let urlString = makeURL(title)
let url = NSURL(string: youtubeApi)
// cancel task, if there is already one
task?.cancel()
// setup new request
let request = NSURLRequest(URL: url!)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
// No errors occured
do {
// some JSON processing
// complitionHandler is returned here
} catch let parseError {
// Some other error
print(parseError)
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("YoutubeSearch Error: '\(jsonStr)'")
}
}
// execute request
task.resume()
return task
}
}
The code works fine in the simulator. I get a valid JSON. But on tvOS it throws an error telling me the certificate is invalid:
NSUnderlyingError=0x13e207d70 {Error Domain=kCFErrorDomainCFNetwork Code=-1202 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=, _kCFNetworkCFStreamSSLErrorOriginalValue=-9814, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9814, kCFStreamPropertySSLPeerCertificates={type = immutable, count = 3, values = (
0 :
1 :
2 :
)}}}, NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “www.googleapis.com” which could put your confidential information at risk., NSErrorFailingURLKey=https://www.googleapis.com/youtube/v3/search?videoEmbeddable=true&videoType=any&videoDefinition=any&order=relevance&part=snippet&videoDimension=any&q=lets+play+berlin&videoCaption=closedCaption&videoLicense=any&videoSyndicated=true&type=video&videoDuration=short&maxResults=10&key={API-KEY}, NSErrorFailingURLStringKey=https://www.googleapis.com/youtube/v3/search?videoEmbeddable=true&videoType=any&videoDefinition=any&order=relevance&part=snippet&videoDimension=any&q=lets+play+berlin&videoCaption=closedCaption&videoLicense=any&videoSyndicated=true&type=video&videoDuration=short&maxResults=10&key={API-KEY}, NSErrorClientCertificateStateKey=0})
Yet I wasn't able to nail down the problem. I found Apples Technical Note TN2232 on HTTPS Server Trust Evaluation, but frankly said much to work through while I'm not sure if I just forgot about a simple additional thing.
I've learned that I could disable server trust. But this is not an option for me as the app is supposed to apply at the Apple Store.
Does anybody faced the same problem? Or does anybody have a clue on what to do in order to solve the problem?
Kind regards!

NSURLConnection returning error instead of response for 401

I have a web API that, for a specific request returns status code 200 if everything went ok, and 401 if the user is not logged in based on an Authorization token. Everything works fine if the response status is 200, but doesn't seem to work properly if the response status is 401, returning a connection error with code -1012, while the response is nil.
So, the following code:
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(#"%#", response);
NSLog(#"%#", connectionError);
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
int statusCode = (int)[httpResponse statusCode];
NSLog(#"response status code: %d", statusCode);
will display
2015-04-01 15:58:18.511 MyProject[3618:694604] <NSHTTPURLResponse: 0x155facc0> { URL: *SOME_URL* } { status code: 200, headers {
"Access-Control-Allow-Headers" = "Content-Type, Accept, X-Requested-With";
"Access-Control-Allow-Methods" = "POST, GET, PUT, UPDATE, OPTIONS";
"Access-Control-Allow-Origin" = "*";
Connection = "keep-alive";
"Content-Type" = "application/json";
Date = "Wed, 01 Apr 2015 12:58:14 GMT";
Server = "Wildfly 8";
"Transfer-Encoding" = Identity;
"X-Powered-By" = "Undertow 1";
} }
2015-04-01 15:58:18.513 MyProject[3618:694604] (null)
2015-04-01 15:58:18.513 MyProject[3618:694604] response status code: 200
if the response status is 200, while if the status code is 401, I will get:
2015-04-01 16:05:55.988 MyProject[3633:695836] (null)
2015-04-01 16:05:55.992 MyProject[3633:695836] Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x146137c0 {NSErrorFailingURLKey=*SOME_URL*, NSErrorFailingURLStringKey=*SOME_URL*, NSUnderlyingError=0x1459e6d0 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1012.)"}
2015-04-01 16:05:55.992 MyProject[3633:695836] response status code: 0
If I do the same request using Postman or an Android device, I will get status code 401 with the following headers(copied from Postman):
Connection → keep-alive
Content-Length → 30
Content-Type → application/json
Date → Wed, 01 Apr 2015 13:07:34 GMT
Server → Wildfly 8
X-Powered-By → Undertow 1
Is there any fix or maybe a library that could give me some accurate response status? I searched a bit about the -1012 error, but couldn't find much and I don't really want to base on that.
Edit: after a bit of research I found the following statement on Appl's documentation: "If authentication is required in order to download the request, the required credentials must be specified as part of the URL. If authentication fails, or credentials are missing, the connection will attempt to continue without credentials."
But then how can I know if this error will be after a 401 status? Can it appear after another type of request?
to check the 401 error, you can do this:
if (error != nil && error.code == NSURLErrorUserCancelledAuthentication) {
// do something for 401 error
}
hope this help
In order to get the 401 status code, I think you'll need to implement protocol NSURLConnectionDelegate and then connection:didReceiveAuthenticationChallenge:.
So, you'll also need to pass the delegate, maybe using [NSURLConnection connectionWithRequest:request delegate:self].
And, if you aren't trying to implement the authentication challenge, I would rather always return the 200 status code, but with different json content.
Hope it can help.
I have a web API that, for a specific request returns status code 200
if everything went ok, and 401 if the user is not logged in based on
an Authorization token. Everything works fine if the response status
is 200, but doesn't seem to work properly if the response status is
401, returning a connection error with code -1012, while the response
is nil.
I've run exactly into the same problem, REST API call returns 401 in Android and Postman, but status code 0 in iOS with a connection error with code -1012.
You can find more information about this problem in this SO post.
Seems to be an iOS bug (or at least very strange approach) happening both with async and sync requests.
I'm posting this just in case this might be useful for others bumping into the same issue. What I did in the code to manage the 401 status, right after the request, is to call a method that checks each managed http status code.
The method receives (NSError **)error and [(NSHTTPURLResponse *)response statusCode].
This is the 401 part - uses the error details stored inside userInfo structure.
// Auth failed or token problems
if (statusCode == 0 && [error userInfo] != nil) {
// Get error detailed informations
NSDictionary *userInfo = [error userInfo];
NSString *errorString = [[userInfo objectForKey:NSUnderlyingErrorKey] localizedDescription];
// If error message is of type authFailed or returns iOS code -1012 meaning auth failed
if ([errorString containsString:#"kCFErrorDomainCFNetwork"] || [errorString containsString:#"-1012"]) {
NSLog(#"%# - ConnectionError - Code 401 - Cause: authentication failed, token is invalid or expired", type);
} else {
NSLog(#"%# - ConnectionError - Cause: generic auth error", type);
}
// Alert user that auth failed
...
}
The other way is to check directly for this error code (-1012) as suggested by #ThuanDINH above. (edited the answer for objective c).
My code can be changed into:
// Auth failed - token problems
if (statusCode == 0 && [error code] == NSURLErrorUserCancelledAuthentication) {
// If error code is UserCanceledAuthentication
MPLog(MPLogLevelInfo, #"%# - ConnectionError - Cause: authentication failed, token is invalid or expired", type);
// Alert user that auth failed
...
}
But in this way you will not handle all other errors (you need to switch on each NSURLError code).
Here you can find the SO question with the list of all the NSURLError codes.
Based on Apple documentation https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html,
Note: NSURLSession does not report server errors through the error parameter. The only errors your delegate receives through the error parameter are client-side errors, such as being unable to resolve the hostname or connect to the host. The error codes are described in URL Loading System Error Codes.
Server-side errors are reported through the HTTP status code in the NSHTTPURLResponse object. For more information, read the documentation for the NSHTTPURLResponse and NSURLResponse classes.
We need to make sure that we do not cancel the session in our code. For example, I was calling NSURLSessionAuthChallengeCancelAuthenticationChallenge in didReceiveChallenge delegate method, when previousFailureCount > 1. This was suppressing 401 response and also call to didReceiveResponse.
When I changed above value to NSURLSessionAuthChallengePerformDefaultHandling, I am receiving 401 Unauthorized response in didReceiveResponse delegate method and works as expected.