WinHttp: How to use a temporary certificate store? - c

I have a C++ application that makes a HTTPS connection to one of our servers.
In my ideal world, I would like the following to occur:
App Starts
App makes Windows trust the server's root CA (no GUI please, just system calls)
App talks to server, does its work, etc.
App makes windows forget about the server's root CA
done
I do NOT want this root CA to necessarily be trusted by other apps. Therefore I don't want to install the cert system-wide.
I also would like it if the user did not need Admin privileges.
My initial plan was to create an in-memory (CERT_STORE_PROV_MEMORY) store, add my cert to that, then add that in-memory store to the system store using CertAddStoreToCollection.
While all the CryptoAPI function calls succeed, WinHttp does not like it.
Here is the skeleton of what I'm doing - perhaps someone knows a trick?
Or perhaps this is wrong-headed in the first place?
hMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY, ...);
pCert = CertCreateCertificateContext(..., pCertBytes, ...);
CertAddCertificateContextToStore(hMemStore, pCert, ...);
hRootStore = CertOpenSystemStore(NULL, "ROOT");
CertAddStoreToCollection(hRootStore, hMemStore, ...);
// Then later on...
WinHttpSendRequest(...)
A few notes:
Everything works when I use WinHttp's SECURITY_FLAG_IGNORE_UNKNOWN_CA, so I'm fairly sure this really is the issue.
I have already seen this SO question - it is close, but does not address the issue of making the cert only temporarily trusted, while the app runs.
Thanks!

Since you don't want other applications to trust this cert, you need to do part of the certificate validation yourself. Disable the CA check with the option SECURITY_FLAG_IGNORE_UNKNOWN_CA and then get the call back for connecting to the server WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER. In that callback fetch the cert with WINHTTP_OPTION_SERVER_CERT_CONTEXT and do your validation. Cancel/Close the request if it's not who you want, continue the request if it's correct.

Related

Regression on SQL Server Connection from Standard Logic App

I have been developing Standard Logic Apps with SQL Server successfully for some time, but suddenly can no longer connect. I'm using Azure AD Integrated as my Authentication Type, which I know is OK as I use the same credentials in SSMS. If I try to create a new credential, it is apparently successful but on save the Logic App says "The API connection reference XXX is missing or not valid". Something has changed, but I don't know what ... help!
per above, this was submitted to M/S and has been resolved as follows: the root cause is if a Logic App Parameter name includes an embedded space the problem with SQL connections is triggered. This is a pernicious problem, as the error message is quite unrelated to the root cause. Further, since embedded spaces are supported in Logic Apps e.g. in Step Names, it is easy to assume the same applies across the board.

Limit the usage of Kerberos TGTs

I'm pretty new to Kerberos. I'm testing the Single Sign On feature using Kerberos. The environment: Windows clients (with Active Directory authentication) connecting to an Apache server running on Linux machine. The called cgi script (in Perl) connects to a DB server using the forwarded user TGT. Everything works fine (I have the principals, the keytab files, config files and the result from the DB server :) ). So, if as win_usr_a on Windows side I launch my CGI request, the CGI script connects to the remote DB and queries select user from dual and it gets back win_usr_a#EXAMPLE.COM.
I have only one issue I'd like to solve. Currently the credential cache stored as FILE:.... On the intermediate Apache server, the user running the Apache server gets the forwarded TGTs of all authenticated users (as it can see all the credential caches) and while the TGTs lifetime are not expired it can requests any service principals for those users.
I know that the hosts are considered as trusted in Kerberos by definition, but I would be happy if I could limit the usability of the forwarded TGTs. For example can I set the Active Directory to limit the forwarded TGT to be valid only to request a given service principal? And/Or is there a way to define the forwarded TGT to make it able to be used only once, namely after requesting any service principal, become invalid. Or is there a way the cgi script could detect if the forwarded TGT was used by someone else (maybe check a usage counter?).
Now I have only one solution. I can define the lifetime of the forwarded TGT to 2 sec and initiate a kdestroy in the CGI script after the DB connection is established (I set that the CGI script can be executed by the apache-user, but it cannot modify the code). Can I do a bit more?
The credential caches should be hidden somehow. I think defining the credential cache as API: would be nice, but this is only defined for Windows. On Linux maybe the KEYRING:process:name or MEMORY: could be a better solution as this is local to the current process and destroyed when the process is exited. As I know apache create a new process for a new connection, so this may work. Maybe KEYRING:thread:name is the solution? But - according to the thread-keyring(7) man page - it is not inherited by clone and cleared by execve sys call. So, if e.g. Perl is called by execve it will not get the credential cache. Maybe using mod_perl + KEYRING:thread:name?
Any idea would be appreciated! Thanks in advance!
The short answer is that Kerberos itself does not provide any mechanism to limit the scope of who can use it if the client happens to have all the necessary bits at a given point in time. Once you have a usable TGT, you have a usable TGT, and can do with it what you like. This is a fundamentally flawed design as far as security concerns go.
Windows refers to this as unconstrained delegation, and specifically has a solution for this through a Kerberos extension called [MS-SFU] which is more broadly referred to as Constrained Delegation.
The gist of the protocol is that you send a regular service ticket (without attached TGT) to the server (Apache) and the server is enlightened enough to know that it can exchange that service ticket to itself for a service ticket to a delegated server (DB) from Active Directory. The server then uses the new service ticket to authenticate to the DB, and the DB see's it's a service ticket for win_usr_a despite being sent by Apache.
The trick of course is that enlightenment bit. Without knowing more about the specifics of how the authentication is happening in your CGI, it's impossible to say whether whatever you're doing supports [MS-SFU].
Quoting a previous answer of mine (to a different question, focused on "race conditions" when updating the cache)
If multiple processes create tickets independently, then they have no
reason to use the same credentials cache. In the worst case they would
even use different principals, and the side effects would be...
interesting.
Solution: change the environment of each process so that KRB5CCNAME
points to a specific file -- and preferably, in an
application-specific directory.
If your focus in on securing the credentials, then go one step further and don't use a cache. Modify your client app so that it creates the TGT and service tickets on-the-fly and keeps it private.
Note that Java never publishes anything to the Kerberos cache; it may either read from the cache or bypass it altogether, depending on the JAAS config. Too bad the Java implementation of Kerberos is limited and rather brittle, cf. https://steveloughran.gitbooks.io/kerberos_and_hadoop/content/sections/jdk_versions.html and https://steveloughran.gitbooks.io/kerberos_and_hadoop/content/sections/jaas.html

AppHarbor - Same SQL Server in more than one application

I am using the variables to configure the same "connection string" between two applications, since the two do access the same database of users.
Can I set the same SQL Server (Nano 10GB) in more than one application to use transformation for web.config?
This is not currently possible since there is no way to have the connectionsstring injected into other applications than the one that has the add-on provisioned. Feel free to add this as a feedback suggestion.
It is possible, but requires some legwork. Basically you need to have one app with a known location (URL is fine) that the others can ask for the Connection String. The hard part is doing it securely enough. I'm partway there...
I've rigged up a system where you have a password that both of your Apps know in AppSettings, and then have the Secondary Website send a Public Key to the Primary Website with the password. Who then encodes the connection string, and sends it back.
The password CAN be injected by Appharbor when it does a deploy. And the connection string is also setup on the deploy. Ideally you'd use SSL but I don't have that setup and it makes life hard when working locally.
Proof Of Concept: https://bitbucket.org/Rangoric/database-coordination/overview
It does work, just start both of the website projects in there, and go to http://localhost:4002/Database and you will see what is in the connection String of the Primary website.
EDIT: I just realized that since you can piggyback the SSL Cert of appharbor with the free subdomain they give you, you can use that URL for added security if you don't have your own SSL cert.

silverlight accept invalid certificate

I'm doing https web requests in silverlight using "WebRequest"/"WebResponse" framework classes.
Problem is: I do a request to an url like: https://12.34.56.78
I receive back a versign signed certificate which has as subject a domain name like: www.mydomain.com.
Hence this results in a remote certificate mismatch error.
First question: Can I somehow accept the invalid certificate, and get the WebBresponse content ? (even if it involves using other libraries, I'm open to it)
Additional details: (for those interested on why I need this scenario)
I'm trying to give a client access to a silverlight app deployed on a test server.
Client accesses the silverlight app at: www.mydomain.com/app
Then I do some rest requests to: https://xx.mydomain.com
Problem is I don't want to do requests on https://xx.mydomain.com, since that is on our productive server. For this reason I use https://12.34.56.78 instead of https://xx.mydomain.com.
Client has some firewalls/proxies and if I simply change his hosts file and map https://xx.mydomain.com to 12.34.56.78, web requests don't resolve to the mapped IP.
I say this because on his network webrequests fail if I try that, on my network I can use the hosts changing without problems.
UPDATE: Fixed the problem by deploying test releases to an alternative: https://yy.domain.com and allowing the user to configure for test purposes, the base url to which I do requests to be: https://yy.domain.com.
Using an certificate that contained the IP in the subject or an alternative subject would've probably worked too, but would have cost some money to be issued by a certified provider and would not be so good because IP's might change.
After doing more research looks like Microsoft won't add this feature too soon, unless there's a scenario for non-testing/debugging uses.
See: http://connect.microsoft.com/VisualStudio/feedback/details/368047/add-system-net-servicepointmanager-servercertificatevalidationcallback-property

Making a WP7 HttWebRequest POST with an untrusted cert?

I'm working on a Windows Phone 7 application that makes a REST service call. The third party that hosts the web services has an invalid certificate in the current environment. When I hit the URL in Firefox, I get a warning about the cert and I am asked if I want to continue. I'm also using the Poster FF extension to test the call. It works with Poster if I first accept the invalid cert in Firefox. If I don't, then POSTER wont make the request.
In my WP7 Emulator, I can't make the request at all. I get a 404 at the EndGetResponse method. I making the same request as in Poster, so I know there is nothing wrong with the request. I have successfully hit another web service using the same code (no certs involved), so I don't think it's the code. The only thing I can think of is that WP7 doesn't allow requests to an invalid cert. Has anyone had experience with this situation? Is there any way around it?
Is there a way I can tell my app to accept all communication, even if there is an invalid cert?
There is sadly no way to do this on the phone. Ordinarily, i.e. on the desktop this simple line of code will disable certificate checking.
System.Net.ServicePointManager.ServerCertificateValidationCallback = (se, cert, chain, sslError) => { return true; };
If you look at the ServicePointManager on the phone, there's no callback to hook into. It's a massive pain in the arrrrse.
Have you considered writing to the service owner and asking why they're being bad internet citizens? (essentially, what you're seeing here is web security in action, for better or worse)
As Matt says, you might be able to code a simple relay on a web server. It doesn't have to be a special service, but maybe just a web page that does the call for you and spits out RAW text or XML. Your phone client just GETs this page and picks through the response manually.
Where there's a will there's a way.
Luke
You need to install the root CA cert of the issuing party on the phone.
You can do this by emailing the RootCA to the user of the phone. They click on the attachement and it will prompt them to ask if they want to install the certificate on the phone.
Once you have done that your requests should go through.
I dont believe there is a way to do this programatically in your app however.
I'm not aware of a way to install additional certificates on the phone.
In this situation I'd create a proxy service between your app and the 3rd party site and have your app call that. If you need to, you could put the proxy behind a valid cert.

Resources