Friday, August 4, 2017

Visual Studio Missing "Open Project/Solution"

Background

A very weird thing happened to me the other day...

I have a client that was having trouble running SQL Relay to run on Windows 7 x86. After getting a Windows 7 x86 VM working, I ran into some of the same problems.

Hmm...

Well, my x86 packages are built on Windows 8.1, with the correct switches for Windows 7 compatibility, but who knows, maybe I should just build it on Windows 7 to see if I get better results.

The Problem...

So, I installed Visual Studio 2013 Community, which is what I use on Windows 8.1, and got everything to compile and run. But, to build packages, I needed to use Visual Studio Pro 2010, because it actually supports building deployment packages, unlike the free versions.

No problem, I own a copy of that, so I installed it too.

Post-install, the UI looked weird and the File menu had an "Open File..." option but no Open Project/Solution, or New Project/Solution, or anything like it. Opening the deployment project with Open File just opened the file itself in a text editor.

What the heck?

The web suggested Tools -> Import and Export Settings... -> Reset All Settings.

This did nothing.

The Solution...

I ultimately discovered that installing VS 2013 first had caused the problem.

To uninstall 2013 completely, I used:

vs_community.exe /uninstall /force

...from the install DVD image.

To uninstall VS 2010 and start fresh, I used the "Uninstall a program" link in the Control Panel. I also removed the various things that I'd seen the VS 2010 installer install the first time, like Dotfuscator, Tools for Office Runtime, various SQL Server-related things, and Silverlight. Unfortunately I don't have an exact list of them now, and looking at it now, it's not clear what was installed by VS 2010 and what was installed alongside something else. It's also not clear how important removing them is, so it might not matter. I just did it to be thorough.

After that, I re-installed VS 2010 and the UI looked correct. Installing VS 2013 afterward didn't hose 2010 either.

All of this took hours and hours.

Why...

Why does it matter what order you install them in?

After much digging...

It appears that every time you install a new version of VS, it attempts to emulate your UI settings from any existing version. This works OK when upgrading from an older version of VS because it already existed prior to the invention of the newer version. If you already have a newer version installed though, the old version might get confused trying to make sense of its newfangled configuration. Apparently this happens when 2010 Pro tries to read the settings from 2013 Community.

Ha!

Well, at least I'll know to avoid that in the future.

Sketchy Windows 7 x86 Activation

Man!

I bought a copy of Windows 7 Home Premium (32-bit) from a guy on eBay, and what I got in the mail was nothing like I'd hoped I'd get. I'd hoped for a new, in-the-box copy. Instead, I got a disc that said something like "Intended for distribution with a refurbished PC" on it, and an obviously peeled-off product key stuck to the back of the sleeve.

Great.

In hindsight, it was probably foolish to expect more for $27.99. Would it even work?

Well, kind-of. I was able to install it in VMware and the key worked at installation time, but when I tried to Activate Windows, it failed with an error saying that Microsoft had blocked that key!

Wow.

So, maybe the guy bought a refurbished laptop which eventually died, and he resold the disc that came with it, along with the product key that he peeled off of the laptop???

Conceptually, that seems like the kind of thing that something one ought to be able to do. But, of course, logistically, if Windows 7 had already been activated on the laptop, then after it died, there's no good way for Microsoft to know that, or any process that I know of to deactivate a key, and it ends up being up to the new owner to sort it out.

Fortunately, I was able to do so, very easily.

MS has a new (well, new as of August 2017) online chat thing that you can use for customer support at https://support.microsoft.com/en-us/contactus/. I typed in my problem, it gave me a potential solution, which didn't work, and then asked me if it solved the problem. Clicking No gave me the option of chatting with a guy, and the guy was able to get everything going.

It did require a bit of legwork though. I had to take a photo of the product key and a screenshot of the eBay order and put them on the VM's desktop, basically as proof-of-purchase. Then, I had to go through some steps to let him take over the PC. He looked at the images, "convinced his supervisor" that I had legitimately purchased the product, generated a new key, activated Windows with that key, and left me a copy of the key on the desktop.

Excellent!

So, if you find yourself in a similar situation, you may not just be out $27.99. There is hope.

Windows 7 - Get Genuine!

I'm sure this has happened to someone else...

Years ago I bought a cheap laptop from WalMart, an Acer Aspire One 725 - 0802 to be exact, which came with Windows 7 Home Premium. Given how inexpensive it was, I expected to have to replace it a year later, but no, it just kept bumping along until the paint was worn off of almost every key. One day though, it just wouldn't turn on any more.

Between backups and the cloud I was able to move the software and data to a new laptop, but I didn't want the copy of Windows 7 to go to waste, so I did a P2V conversion by pulling out the hard drive, putting it in an external case, dd'ing the drive image, etc. I also saved the product key, just in case.

I ran it in VMware for a while, and then one day the screen turned black and I got "Get Genuine" messages every time I'd try to do anything. I tried to Get Genuine, over and over, but every time it failed, telling me to contact Acer. Attempts to Activate Windows just sent me to a Windows 10 FAQ.

No good!

For a long time, I tolerated the messages, but eventually called customer support to try to sort it out. I explained everything to them, and the fix was remarkably simple.

Open a command prompt and run:

slui 3

Then, enter the product key.

That's all.

At least on my side. What I don't know is whether they had to do something on their side too, to allow it.

Either way though, it was ultimately quite simple. So, if you've run into the same problem, try slui by itself, and if that doesn't work, call customer support and walk through it with them. They don't appear to just outright reject these kinds of activations because of the OEM key.

The only remaining problem was a black background. That was easily fixed by right-clicking on the desktop, selecting Personalize, and selecting the Windows 7 theme.

Good as new!

Thursday, April 6, 2017

Oracle TLS/SSL Encryption Tutorials

So, you want to secure communications between your application and an Oracle database with TLS/SSL...

Most TLS/SSL-capable servers are secured by generating a private key, getting a certificate, and adding a few lines to a config file to tell the server the locations of the cert and key files. Of course, if you generate the certificate yourself, then you also have to tell the server about your fake certificate authority. But, for most apps, that's it. Three parameters in a file somewhere: cert, key, and ca.

With Oracle, the idea is similar, but the details are very different.

Rather than storing certificates and keys in files and providing the paths to them in a config file, you store them in an Oracle "wallet" and provide the path to the wallet.

While Oracle wallets are more secure than flat files, the security features introduce some interesting quirks that are worth reviewing before attempting an implementation.

When you're ready to take the plunge, tutorials follow:

Saturday, December 24, 2016

Updating Your App to Support OpenSSL 1.1.0

Introduction

OpenSSL 1.1.0 introduced several API-breaking changes, and with distributions starting to use it, I found myself scrambling to get my software working. I found various docs stating that 1.1.0 changed things, but nothing that clearly stated: "if you have this now, then change it to this..." So, that's what I'll do here, and hopefully it will help you if you find your app in the same situation.

Deprecated "method" Functions

Lots of "method" functions like TLSv1_server_method() and SSLv23_client_method() and TLSv1_2_method() are deprecated in OpenSSL 1.1.0, and if you compile your software with -Werror, then that presents a problem.

All you can call now is one of:

  • TLS_method()
  • TLS_client_method()
  • TLS_server_method()

If your code allowed the user to select a SSL/TLS mode then it can't do it by calling a mode-specific function any more. It'll have to select the mode some other way that I'm not aware of. The new methods negotiate the most modern mode supported by the client and server. It's not immediately clear how to override that, or if you can. If someone knows a way, please leave a comment below.

It's easy enough to replace function calls, but if you want to support older versions, then you have to add tests for the old and new functions to your configure script and add all kinds of #ifdefs, and so forth. Actually, since various methods like these have been added over the years, you may already have such tests and #ifdefs (I did) and it won't be so bad.

Deprecated ASN1_STRING_data
unsigned char *ASN1_STRING_data(...);

has been replaced with

const unsigned char *ASN1_STRING_get0_data(...);

This is a straightforward replacement, but note the const'ness of the return value of the new function. If you're using C++ then you may have to change the type of the variable it's being assigned to (or un-const it).

Again, this is a brand new function, so, configure tests and #ifdefs.

Opaque EVP_PKEY

The EVP_PKEY struct (public key struct) is opaque now. The header files declare that an EVP_PKEY struct exists, but the definition is hidden up in the library. The error you get (with g++ at least) is fairly obtuse though, complaining about a forward declaration and an invalid use of an incomplete type. The error just means that the struct is opaque.

Fortunately there are a bunch of functions that return the various components of the struct.

I had to replace code to get the key type like:

EVP_PKEY *pubkey = X509_get_pubkey(c);
...
int t = pubkey->type;

with code like:

EVP_PKEY *pubkey = X509_get_pubkey(c);
...
int t = EVP_PKEY_base_id(pubkey);

Note that there IS an EVP_PKEY_type() function, but it does NOT return the "type" member of the struct. Ha! Not super intuitive, but the change is still straightforward.

Similarly, I had to replace code to get the key itself like:

EVP_PKEY *pubkey = X509_get_pubkey(c);
...
const unsigned char *key = pubkey->pkey.ptr;

with code like:

EVP_PKEY *pubkey = X509_get_pubkey(c);
...
const unsigned char *key = EVP_PKEY_get0(pubkey);

I'm not sure when those functions were introduced, but they appear to be available in OpenSSL 1.0.x but not in OpenSSL 0.9.x, so again, if you want to support really old versions, then you'll have to add configure tests and #ifdefs.

Opaque X509

The X509 struct is also opaque now. Like the EVP_PKEY struct, you'll have to use functions to access its members.

The one case I needed was slightly trickier though.

In the past, I was getting the signature algorithm name like:

X509 *c = SSL_get_peer_certificate(ssl);
...
char sigalg[256];
OBJ_obj2txt(pvt->_sigalg,256,c->sig_alg->algorithm,0);

But I had to change that code to:

X509 *c = SSL_get_peer_certificate(ssl);
...
char sigalg[256];
OBJ_obj2txt(pvt->_sigalg,256,OBJ_nid2obj(X509_get_signature_nid(c)),0);

Which is a little contrived. In the old code, c->sig_alg->algorithm is an "obj", and I could pass it directly into OBJ_obj2txt. In the new code, I have to get the "nid", convert it to an object, and pass that in. Ideally I'd just get the object to begin with, but there doesn't appear to be an obvious way to do that.

As a side note, the function name X509_get_signature_nid() was a little confusing at first, because it appears to return the "nid" of the signature _algorithm_ as opposed to the signature itself. But I guess the signature itself wouldn't have a "nid", so it makes sense, but it wasn't immediately intuitive to me.

Again, X509_get_signature_nid() was introduced sometime in the 1.0.x series, so you'll have to add a test for it and #ifdefs if you want to support older versions.

Conclusion

The opacity of the structs ought to help OpenSSL be more maintainable in the future. They ought to be able to change the code at will now, without breaking the API or ABI, and that's always good. I did the same kind of thing with my Rudiments library way back, and recently to SQL Relay for that exact reason. Hopefully it will work out well for both of us.

I'm not sure about the TLS_*_method() thing though. It seems like there really ought to be a way to choose a specific SSL/TLS mode. Perhaps there is though, and I just didn't see it. Somebody let me know if they figure that one out.

Saturday, January 9, 2016

Building Ruby From Source With Microsoft Visual Studio

Introduction

Ruby packages are available for Windows, and they can be used to develop Ruby applications, all day long. However, they lack the necessary files to develop Ruby modules in C/C++ and unlike PHP, where you can fairly easily shoehorn the headers into an already-installed package, it's not so easy with Ruby. In fact, to get a hold of the components to shoehorn in, you have to do an entire build from source, so you might as well just do that to begin with.

Fortunately, it's not too difficult.

Prerequisites

For this effort you will need:

  • Microsoft Visual Studio
  • The Ruby source code.
  • A few unixish commands - gunzip and tar. These can be provided by a gnuwin32 installation, a cygwin installation.
  • A text editor. Notepad or vi will do.

The Process

I last did this with Ruby 2.2.0, so I'll use it in this example.

The Ruby source code comes as a tar.gz file. There aren't any .zip files available, or if there are, I'm not sure where to find them. So you'll have to use some unixish commands to extract it.

Move the ruby sources to somewhere convenient and use the unix tools to extract it:

gunzip ruby-2.2.0.tar.gz
tar xf ruby-2.2.0

This should create a directory named ruby-2.2.0

Open the appropriate Visual Studio command prompt. If you plan on building a 32-bit version of Ruby, then open the x86 command prompt. If you plan on building a 64-bit version of Ruby, then open the x64 command prompt.

Navigate into the ruby-2.2.0 directory that was created by the extraction process above.

To get everything to compile and install correctly, I had to edit the file tool\rbinstall.rb and change line 714 to read:

rescue LoadError

This may or may not be necessary with a newer version of ruby, or the line to edit might be different.

Now, configure the build.

For a 64-bit build, run:

win32\configure.bat --prefix=C:\Ruby --target=x64-mswin64

For a 32-bit build, run:

win32\configure.bat --prefix=C:\Ruby --without-ext=fiddle 

(The --without-ext=fiddle command just disables the "fiddle" extension, which I couldn't get to build on 32-bit Windows, for some reason. Your mileage may vary.)

To actually build Ruby, run:

nmake

(This will run for a while.)

When it's done, install Ruby by running:

nmake install

Everything should get installed under C:\Ruby

To make the ruby programs generally accessible, add C:\Ruby\bin to the system PATH as follows:

  • Open the Control Panel
  • Search for Environment
  • Click the link for "Edit the system environment variables"
  • Click "Environment Variables"
  • In the System Variables pane, scroll down and click on Path
  • Click Edit...
  • Append: ;C:\Ruby\bin to the Variable Value.
  • Click OK
  • Click OK
  • Click OK

And that's it. Ruby is now built, installed and accessible.

Hopefully this helps someone out.

Good luck developing your Ruby modules on Windows.

Generating a Missing Import File From a DLL

Introduction

Occasionally I run into software packages for Windows that are missing some of the developer bits. One bit that occasionally gets left out is the import library. The headers are there, the .dll is there, but the .lib file is missing.

It's not impossible to generate a .lib from a .dll though.

Here's how.

Prerequisites

You'll need a few things to do this:

  • Microsoft Visual Studio
  • A few unixish commands - echo, cat, and cut. These can be provided by a gnuwin32 installation, a cygwin installation, or just a second linux or unix system.
  • A text editor. Notepad or vi will do.

The Process

I ran into this issue with Active Perl 5.20, so I'll use it in this example. Adjust accordingly.

First, dump the list of exports from the dll into an exports.in file. Open a Visual Studio command prompt and run some commands similar to the following:

cd C:\Perl64\bin
dumpbin /exports perl520.dll > exports

(adjusting for the path and file name of your .dll)

Now, edit the exports file.

Trim off everything prior to the first function definition. In the perl dll, that was a line like:

          1    0 000295C0 ASCII_TO_NEED

Trim off everything after the last function definition. In the perl dll, that was a line like:

       1249  4E0 001271B0 win32_write

Now, use the unixish commands to create a .def file.

(If you're doing this on a second machine, then you'll need to copy the exports file over to it and then, afterwards, copy the .def file back.)

echo EXPORTS > perl520.def
cat exports | cut -c27- >> perl520.def

Now, use Visual Studio's lib command to build the .lib file.

lib /def:perl520.def /OUT:perl520.lib /MACHINE:X64

Note: In this example, we had a 64-bit DLL. To build from a 32-bit DLL, use the /MACHINE:X86 flag instead.

Currently the .lib file is sitting in the bin directory, but .lib files generally need to go in a lib directory or some other place. So, move it now.

move perl520.lib ..\lib\CORE

You can now clean up if you like.

del exports
del perl520.def

And that's it. You can now link against the .lib file and your app will load the .dll at runtime.

Hopefully these instructions help if you ever find yourself in a similar situation.