My CGI application is trying to use SSPI Schannel to create a TLS connection with another server. http://www.coastrd.com/c-schannel-smtp
The handshake process begins by checking for a certificate in the "MY" certificate store http://msdn.microsoft.com/en-us/library/aa376560(VS.85).aspx
This function returns zero and GetLastError also returns zero!? I assume this is a permissions issue. How do I get this to work without elevating IUSR to administrator for example?
ADDED
Accessing user certificates requires running as the specific user, and accessing the user private key requires either that the user has logged on locally with the password, or that the server is enabled for delegation.
Machine certificates are readable by everyone, but accessing the private key requires admin rights (or local user) unless you adjust the ACL.
ADDED
In this situation, there are no restraints on certificates, but "MY" certificate store is empty and I don't want to buy a certificate just for this.
I am currently using WS2003. The server I am connecting to is gmail.com to send emails using TLS. My code can look for a certificate, but I don't have one. In the reading I have done, it seems like a giant headache to get a certificate, with registration and purchasing and installation, otherwise you just get a temporary solution which is no help. Unless you know of an easy way to get a certificate, this is a lot more trouble than I want to go to just to send email from a CGI app. Is there ANY other way?
I VERY much appreciate your help Joe, but $30/yr x nServers is just not an option. I am wondering if there is a way to hand the task off to another process that IS running with Admin privildeges, like a service perhaps? I could even create an application that is scheduled to read from a given folder and send any emails found there. Other than that, I would have to try elevating the CGI application to Administrator.
ADDED
Goyuix, thank you for the suggestions. The challenge is to provide a stand alone solution without resorting to other libraries like .NET (60MB) or ASP with it's attendant problems.
You are correct, I only need server Authentication. I was not aware it was possible to authenticate one side only. your statement: "Having no client certificate should not stop you from establishing a secure channel for SMTP. You may just need to code around that part of the handshake." turned out to be the solution.
This reminds me of the old plumber joke. The plumber is called to unblock the drain. He takes one look , pulls out a hammer and hits the pipe once. He asks for $180 for 5 mins work itemized as, $30 callout charge and $150 to kown where to hit the pipe.
Thank you both. This has been a LONG uphill slog.
The best option I see is to use a machine certificate and grant permission to the IUSR account to read the private key of the certificate. This is a manual step, but a very easy one that just needs to be done once.
Are there other requirements in your situation that would prevent changing the certificate permissions?
Directions to get started
First, you need a certificate. You can generate your own, but depending on how you want to use it and the other end that will validate it, you might need to purchase one. I won't cover how to generate a certificate. If you have never worked with certificates and certificate authorities before, I recommend learning about them first.
I'll assume you're on Windows Server 2003 unless you comment otherwise.
1) Install the certificate into the machine store. Go to Start | Run and enter in MMC to get a blank MMC console. Go to File | Add/Remove Snap-in. Click the Add button to select the snap-in. Choose Certificates from the list and click Add. Choose the Computer account option, then Next, Finish, Close, and finally OK.
2) Importing the certificate into the Machine Store. Expand out the tree and choose the Personal folder. Right click on Personal and choose All Tasks, Import. Follow the wizard to complete the process. The certificate should now be in the machine store.
3) Adjusting the private key permissions. On Windows 2008, this is added to the Certificate Manager GUI. In Windows 2003, you'll need to download the Windows Server 2003 Resource Kit Tools. Use the following command's format to set permissions:
Where 'LOCAL_MACHINE\My' is the Personal Certificate store in the local machine, 'mycert' is the name of your certificate, and USER_ACCOUNT is the account which will be given read permissions for the private key. You can try the IUSR account, but you might need to use the 'NETWORK SERVICE' depending on the exact context your CGI app is running under. You will need to restart IIS for changes to take effect. The documentation for WinHttpCertCfg covers what it's doing.
You should now have permissions to access the private key. You will still use CertOpenSystemStore with the MY flag.
Hope that helps.
Edit 2:
An easy place to get a certificate with a recognized authority is GoDaddy. You can get an SSL cert valid for 1 year for $30. There are other places that might be cheaper if you hunt around a bit. It's not too difficult to do. Most of the sites are very user friendly and make it easy to buy a cert.
Since you are doing mutual authentication, you'll need a certificate with a valid authority, and not just a self-signed one which you can create yourself because the Gmail server would have no way to verify it.
The only reason that the schannel code is trying to crack open the "MY" store is to look for a potential certificate that can be used for client authentication as part of the initial handshake. In your example, I would imagine you really only care about server authentication (e.g. make sure your client is talking to the server it thinks it is). Having no client certificate should not stop you from establishing a secure channel for SMTP. You may just need to code around that part of the handshake.
If you need client authentication as well, then you are probably going to have to either:
As for fixing the linked code... well - I would suggest trying the SmtpClient code that comes with the .NET framework if that is an option. It supports encrypted communications and should, in theory, "just work". Is managed C++ even an option? Or better yet, just write an ASP.NET handler for this?
http://msdn.microsoft.com/en-us/library/system.net.mail.smtpclient_members.aspx
You may also want to try asking some related code questions on StackOverflow.com, people there might be able to help as well.