Showing posts with label security. Show all posts
Showing posts with label security. Show all posts

Tuesday, 29 March 2016

HTTPS Support for a Casablanca Client


This post is a continuation of a previous one about SSL and Casablanca C++ REST-API library by Microsoft. There we added SSL support to a Casablanca server. This time we'll do it on the client side. At the first sight it seems to be simple, just write:
  web::http::client::http_client restClient(U("https://xxx.yyy.zzz"));
  auto response = restClient.request(web::http::methods::GET);
and go on! As we saw, the only thing to do is to use a HTTPS URI. Nothing more to do? Not really! The main problem when adding SSL support to the client occurred to be the error handling. More specifically, I wanted to differentiate between an SSL error and a simple no-connection error.

Casablanca uses the new standard std::error_condition/error_category classes for that. The problem is, these classes are yet poorly understood by programmers (at least by me, because it is so new)*, and, which is much worse, that their usage by Casablanca (as of v.2.5.0) isn't consistent between Windows and Linux code!

On Windows, there is a special windows_category defined for system errors, while for Linux the standard std::system_category is used. Worse, the error codes forwarded there come from Boost ASIO, which in its turn just forwards OpenSSL's error codes. Which again depends on the library version :-/.

As to tame this chaos a little, the following little helper class was born:
class CCasablancaClientErrorCode 
{
public:
  CCasablancaClientErrorCode(int errCode) : _errCode(errCode) {};
 
  /**
    Check and translate to POSIX-conforming system error code.

    For HTTP connection problems following codes are used by Casablanca:
        std::errc::host_unreachable, std::errc::timed_out, std::errc::connection_aborted
  */
  bool IsStdSystemError(std::errc& stdErrorCode) const
  {
#ifdef _WINDOWS
    const std::error_condition ec = utility::details::windows_category().default_error_condition(_errCode);
#else  
    const std::error_condition ec = std::system_category().default_error_condition(_errCode);
#endif
    if (ec.category().name() != genericCategoryStrg) 
    {
      return false;
    }
    else
    {
      stdErrorCode = std::errc(ec.value());
      return true;
     }
  }
 
  /**
    Check if the reported error comes from SSL.

    There is only one, generic server SLL certificate error at the moment!
  */ 
  bool IsSslError() const
  {  
#ifdef _WINDOWS
    const std::error_condition ec = utility::details::windows_category().default_error_condition(_errCode);

    if (ec.category() == utility::details::windows_category())
    {
      return _errCode == ERROR_WINHTTP_SECURE_FAILURE;
    }
    else
    {
      return false;
    }
#else
    const std::error_condition ec = std::system_category().default_error_condition(_errCode);

    if (ec.category().name() == genericCategoryStrg)
    {
      return false;
    }
    else
    {
      // ??? OPEN TODO:::: must test, but it will depend on the SSL version !!!
      // - patch Casablanca's ASIO code?
      // return _errCode == 336458004; //== 0x140DF114  // OpenSSL error code  ??OR?? 335544539 == 0x140000DB

      return true; // should be SSL 
    }
#endif
  }

private:
  int _errCode;
};
Note that on Windows, only a single generic SSL error code is supported by Casablanca 2.5. If we wanted to differentiate between SSL error types, we'd have to patch Casablanca code (install a special callback handler to report the context of the HTTP error). I didn't make it, as generic SSL error was good enough for my customer.

Now now we can use this helper class like that:
  CCasablancaClientErrorCode clientErrCode = e.error_code().value();
  std::errc sysErrCode;

  if (clientErrCode.IsStdSystemError(sysErrCode))
  {
    switch (sysErrCode)
    {
    case std::errc::host_unreachable:
      // no connection error!
      break;
    default:
      // other error (std::errc::timed_out, std::errc::connection_aborted)
    }
  }
  else if (clientErrCode.IsSslError())
  {
    // SSL error!
  }
Having done that, the HTTPS support on the Client side was ready.

Update: As mutual authentication wasn't required it this project I didn't spend much thought on that feature, assuming everything would be OK. Unfortunately, prompted by a question of a reader, I checked up my local and also with newest Casablanca code in Github but unfortunately I couldn't find any trace of support for mutual authentication. As it seems it's not yet implemented (05/08/2017).

--
* I won't explain the workings of std::error_category here, for the confused readers this was already done here (parts 1 to 5, I said it's not a piece of cake).

Sunday, 20 September 2015

HTTPS Support for a Casablanca Server and Certificate Error 1312


In the previous post about Casablanca C++ REST framework I said that our next task would be adding HTTPS support to our solution. So let's do it.

1. The principle

We start with the server side. On the surface it is rather simple, you just specify the protocol the server is using to be "https://" and voila, everything is done. This is done for example like that:
  _restListener = http_listener(U("https://localhost:8111/test"));
But if we peek into the code, we'll see that server-side HTTPS is only supported for Windows as for now (Casablanca 2.5.0). OK, let's test it! We start the server, let Chrome get some data from the newly created SSL-URL*, and... it won't work, apparently there's no such URL! What? We already started our server there, and it's running.

After a second peek into Casablanca's code, we learn that it's leveraging Windows HTTP Server API, but does not configure any HTTPS support by itself. Then we learn from MSN docs, that this will be usually done in the configuration step, before the HTTP server is started. Apparently a programmatic solution is possible too, bu we start with the simple one (or so we think...)**.

In short, we have to attach a server certificate to a port on the machine where our server runs (i.e. our developer machine, at least in this post). For that, we first have to create a new certificate.

2. First try

For the sake of our tests we want to create a self-signed certificate. On Windows we can use the MakeCert.exe tool for that. So I opened the VisualStudio developer console and typed***:

  makecert.exe -sr LocalMachine -ss Root -a sha512 -n "CN=my_machine_name" -sky exchange -pe -r

as to create a self-signed (-r) cert for local machine (required for the add sslcert step later), export it's private key (-pe), use if for exchange (-sky) and store it straight away into the trusted Root Certification Authorities store. OK, it worked.

Next we open the MMC, check that the certificate is there and it has no errors. Don't know how? It's explained several times on the Web, for example here.

Now we need only to set the certificate for server's IP address. The command for that is :

  netsh http add sslcert ipport=0.0.0.0:8111 certhash=XXXX appid={yyyyy}

For the certhash we can use the thumbprint from certificate's Properties window in MMC, for the application ID the most frequent advice is to use the ID of the IIS Server, but as we don not even have it installed on our machine, we prefer to use an empty GUID: {00000000-0000-0000-0000-000000000000}, it's allowed too! Should be working OK!

Alas the dreaded Error 1312 showed it's ugly head:

  Certificate add failed, Error: 1312 A specified logon session does not exist. It may already have been terminated.

WTF? What is that supposed to mean? There are many reasons, like bad certificate hash (nope, double-checked it), a missing Windows hot-fix (nope, it's 2010, already installed), not exported private key (nope, we did it), some mysterious cases when certificates get renewed (nope, there are fresh here), etc, etc. But definitely not a problem with a logon session, that much is true!

3. The second try

What should we do? As always the advice is: go back to the last known working setup. As to do this, I followed advice in this blogpost quite meticulously, and created two certificates:

  makecert -sk testRootCA -sky signature -sr localmachine -n "CN=RootTrustedCA" -ss TRUST -r RootTrustedCA.cer

  makecert -sk testServer -ss MY -sky exchange -sr localmachine -n "CN=Server" -ic RootTrustedCA.cer -is TRUST Server.cer -pe


The first one is supposed to be the base and trusted one, the second to reference the first. That didn't cut it either, because the RootTrustedCA still wasn't trusted - I had to add it to the Root store using MMC (don't know how? - look here).

This time, I didn't want to type the certificate hash and used this nice tool to apply the certificate to the desired IP address, and guess what - it worked! The last problem was, that the domain and certificate's names didn't match, so I created a cert with my machine's name:

  makecert -sk -ss MY -sky exchange -sr localmachine -n "CN=my_machine_name" -ic RootTrustedCA.cer -is TRUST my_machine_name.cer -pe

 applied it to 0.0.0.0:8111 and, at last, everything worked like a charm:




4. Conclusion

As it seems, add sslcert (an by extension, Windows' HTTP Server API) only supports certificates which reference a base trusted one, and doesn't like the ones from the Root store. Remember: the certificate has to be in the User store and has to be in the computer account (i.e. for the local machine)!

Update: The above conclusion is in principle correct, but only when we the add two small words: "by default"! As explained in a friendly comment, add sslcert accepts a command line switch where the desired certificate store can be specified!

OK, that was a little tiring, we'll add support for the client side in another post.

PS: Later I had to add configuration of the SSL certificates to our server configuration code, lots of Windows  system programming :-/.

--
* I mean TSL, but for historical reasons....

** Of course in the real server we'd will implement programmatic solution for configuration of the SSL options for a given URL. You may look up the HTTP Server API's functions HttpSetServiceConfiguration and HTTPQueryServiceConfiguration

*** not quite, first I tried to create a private certificate referencing an already existing, trusted one with:

  makecert.exe -sr LocalMachine -ss MY -a sha512 -n "CN=my_machine_name" my_machine_name -sky exchange -pe -eka 1.3.6.1.5.5.7.3.1

here the implicit Root Agency certificate is used. The problem here is, that the created certificate was broken, MMC said: "This certificate has an invalid digital signature". After much ado it turned out, that the referenced  Root Agency certificate uses a public key which is too short (only 512 bits!!!) and is thus considered not secure. Thanks for a very informative error message!


Tuesday, 30 October 2007

What can you learn from the bad guys?

Really, is there something you can learn from them? Confucius said some time ago: "I'm always glad to meet another voyager: if it's a pleasant man, I can learn what I can do better, if it's an unpleasant man, I can learn what I shouldn't do!". But can we learn something in apositive sense? In order to be able to answer this, let us return to the realm of IT.

What do the really bad IT-guys do? They break in into systems! They use a host of techniques, and one which is particularly interesting is the "SQL injection" (I personally prefer the more colourful - if slightly incorrect - name "SQL hijacking"). Let's explain it using an SQL example. If we build an SQL query string like this:
query = "SELECT * FROM users WHERE name = ' " + userName + ' ";
Now, if we supply an user name string like, say "dummy' or name not null --", the resulting SQL query looks like*:
SELECT * FROM users WHERE name = 'dummy' or name not null --'
And this will get you the list of all users in the system! If the submitted username is like "xxx'; DROP TABLE users; --" the attacker can even get nasty on the database! Simple but effective!

So what, you'd say, how many bad guys will have direct access to my SQL database? Well, you'd be surprised! If you have a Web application which accesses an SQL database the following scenario is conceiveable. The bad guy invokes your SQL database indirectly requesting an URL in the form:
your.site.de/your_app/ListUsersAction.do?ID=11;UPDATE+USER+SET+TYPE="admin"+WHERE+ID=23
which, when appended to the "SELECT * FROM users WHERE id=" string will grant the attacker the admin privileges! Or, when he requests the URL in the form:
your.site.de/your_app/ListUsersAction.do?ID=11;GO+EXEC+cmdshell('format+C')
the disaster is looming! I don't want to discuss this in detail, as it's not a hack instruction page, but I hope you've got the general idea: this a real problem for the Web application development. Well, that's all very bad behaviour and all, but the question is: why should we learn anything about this?

Recently I was charged with extension of a J2EE web application for one of my clients.They were using a proprietary custom tag JSP library**, whose sources were not available (unfortunately, in a big company that's not so unusual). The custom tag library was rather nice, but as the code was gone, it was not extensible. For example, I couldn't specify the onClick attribute for the custom button tag:

<somelib:button action="someapp/SomeAction.do" image="..." ... ⁄>
Can you see it? Think, think... Yes! Let us try some JSP/Javascript injection:

<somelib:button action="someapp/SomeAction.do \" onClick=\"alert('Gotcha!'); \" " image="..." ... ⁄>
which produces, when iterpreted to HTML, a wonderful:

... url="someapp/SomeAction.do" onClick="alert('Gotcha!')" image="..."
The reason why this is working*** ist the fact that \" isn't interpreted as the end of string sign, as it is escaped with a "\" ! So we have a kind of double bottom here - on one level we have a regular string, which, when interpreted, is transformed into something different sematically - it's the second bottom. Isn't it beautiful? On one level (tags) we have a senseless string, which on the lower level (HTML) gets injected into a page code and starts living its own life! Like a seed coming to life after a hibernation phase. Since then I used this technique in several other places, and it never ceases to amaze me. Look at that: <somelib:help key="start_task" tooltip="Help \" align=\"right\" "/>.

So now we can answer the title question: from the bad guys, we can learn how to extend a non-extensible JSP custom tag library! And yes, Confucius was right: we can learn from every person. Indeed.

---
* here "--" comments out the last apostrofe, but we might as well add some ineffective condition like "and name='yyy" to balance the apostrophes.
** for those of you not doing J2EE: a custom tag is a sort of macro generating HTML code when interpreded on the server side
*** this works on Tomcat, and as Tomcat is the reference implementation of a Servlet container... guess what.