I am having issues when calling CryptUIWizDigitalSign to programatically sign an executable with our public code signing certificate, without showing any UI. The certificate is a Comodo code signing certificate.
It works fine when the timestamp URL parameter is set to null, but whenever I pass anything other than null in, the call fails (returns zero).
The problem is that without a timestamp, there is no countersignature, and so there are signature validity problems further down the line.
Environment is Windows 7 x64. There is a working standard internet connection. It appears from sniffing the network traffic that no attempt is made by CryptUIWizDigitalSign to contact the timestamp server.
I am calling this from .NET via a PInvoke, but I doubt that would make any difference.
Not a lot on the net about this function...
Dim cert As X509Certificate2 = New X509Certificate2("mycert.pfx", "password")
Dim pSigningCertContext As IntPtr = cert.Handle
Dim digitalSignInfo As CRYPTUI_WIZ_DIGITAL_SIGN_INFO
= New CRYPTUI_WIZ_DIGITAL_SIGN_INFO
digitalSignInfo.dwSize = Marshal.SizeOf(digitalSignInfo)
digitalSignInfo.dwSubjectChoice = CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE
digitalSignInfo.pwszFileName = "C:\temp\installer.exe"
digitalSignInfo.dwSigningCertChoice = CRYPTUI_WIZ_DIGITAL_SIGN_CERT
digitalSignInfo.pSigningCertContext = pSigningCertContext
digitalSignInfo.pwszTimestampURL = "http://timestamp.comodoca.com/authenticode"
digitalSignInfo.dwAdditionalCertChoice = 0
digitalSignInfo.pSignExtInfo = IntPtr.Zero
If (Not CryptUIWizDigitalSign(CRYPTUI_WIZ_NO_UI, IntPtr.Zero, vbNullString,
digitalSignInfo, pSignContext)) Then
Throw New Win32Exception(Marshal.GetLastWin32Error(),
"CryptUIWizDigitalSign")
End If
The CRYPTUI_WIZ_DIGITAL_SIGN_INFO type is defined as:
<StructLayout(LayoutKind.Sequential)> _
Public Structure CRYPTUI_WIZ_DIGITAL_SIGN_INFO
Public dwSize As Int32
Public dwSubjectChoice As Int32
<MarshalAs(UnmanagedType.LPWStr)> Public pwszFileName As String
Public dwSigningCertChoice As Int32
Public pSigningCertContext As IntPtr
Public pwszTimestampURL As String
Public dwAdditionalCertChoice As Int32
Public pSignExtInfo As IntPtr
End Structure
Public Const CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE As Int32 = 1
Public Const CRYPTUI_WIZ_DIGITAL_SIGN_CERT As Int32 = 1
Public Const CRYPTUI_WIZ_NO_UI As Int32 = 1
You've applied the MarshalAs attribute on pwszFileName but not pwszTimestampURL, is there any reason for this? They're described identically in the documentation for CRYPTUI_WIZ_DIGITAL_SIGN_INFO :
pwszFileName:
A pointer to a null-terminated Unicode string that contains the path and file name of the file to sign. This member is used if CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE is specified for the dwSubjectChoice member.
pwszTimestampURL:
A pointer to a null-terminated Unicode string that contains the URL for the time stamp.
Fixed - works only within a 32 bit process.
Related
I downloaded the source code for FindPrivateKey.exe.
I use this exe to find the filename and folder for a private key. I have to run this locally on the machine. I am looking for a way to get this information remotely using web api.
FindPrivateKey.exe works by itself as a console app.
But in my webapi code, it does not work (CryptAcquireCertificatePrivateKey returns false)
Is there an obvious reason for this? The web api site has AllowAnonymousAccess enabled, is that why?
I'm having trouble including the code snippet. Summarizing:
StoreName is "My"
StoreLocation is "Local Machine"
//the call below returns false and this is where I am stuck
if (CryptAcquireCertificatePrivateKey(cert.Handle,
acquireFlags, IntPtr.Zero, ref hProvider, ref _keyNumber, ref freeProvider))
{
...
}
I was able to get this to work by first impersonating a user with rights to the private key information. For anyone interested, google the DllImport code below for how to do this.
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int LogonUser(
string lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
public extern static int DuplicateToken(
IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
When using SQLite for windows phone app, I am getting error in sqlite.cs:
path not for found
Here is the path, but when checked path could be found, I hardcoded the path and tried but it didn't work out.
string dbPath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "db.sqlite");
Here is the error
public static Result Open(string filename, out Sqlite3DatabaseHandle db, int flags, IntPtr zVfs)
{
return (Result)Sqlite3.sqlite3_open_v2(filename, out db, flags, "");
#else
return (Result)Sqlite3.sqlite3_open_v2(filename, out db, flags, null);
}
Here path db is coming null.
When I try and process more than a couple of files at the same time (they are created and dumped in a folder at the same time), my service dies.
When I wasn't trying to use a thread and had all the processing (where the code in the ProcessFiles method now is) in the Watcher_Created event, at least one file gets through successfully.
When I added the threading (which I'm pretty sure I have to do for this, but am totally unsure of the exact flow and syntax using the threading), I get the following msg in my ProcessFiles method:
System.ArgumentException: Empty path name is not legal.
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath)
The above msg occurs on the using line:
private static void ProcessFiles()
{
try
{
Thread.Sleep(500);
GetCruiseLineShipName(fullFileName, ref cruiseLine, ref shipName);
using (StreamReader sr = new StreamReader(File.Open(fullFileName, FileMode.Open, FileAccess.Read, FileShare.Read)))
which is obvious, because the "fullFileName" is an empty string. However, it does get set in the Watcher_Created event:
private static void Watcher_Created(object sender, FileSystemEventArgs e)
{
fullFileName = e.FullPath;
}
So, I don't understand why the fullFileName variable is an empty string. I know it must have something to do with the threading I'm trying.
My OnStart event looks like this:
protected override void OnStart(string[] args)
{
FileSystemWatcher Watcher = new FileSystemWatcher(#"C:\DropOff_FTP\MIS");
Watcher.EnableRaisingEvents = true;
Watcher.Created += new FileSystemEventHandler(Watcher_Created);
Watcher.Filter = "*.txt";
Watcher.IncludeSubdirectories = false;
Watcher.InternalBufferSize = 64;
Thread t = new Thread(new ThreadStart(ProcessFiles));
t.Start();
}
Can someone PLEASE inform me how I can use the FileSystemWatcher to process multiple files that are dumped in there at the same time. If I need to use threading, could you please supply how I would use the thread based on the code above?
btw, I'm using the 4.0 framework.
Conceptually something is wrong here. If I understand you correctly, you have two files created in the same folder with short time difference. Then you receive the first event and set the name of ONE file in the global variable fullFileName and you expect that the running thread process this file using the global variable, but in the same time another event Created happens and you change the global variable that the separate thread is processing
I will try to change you code in this way:
the OnStart method loose the code that starts the Thread
the Watcher_Created event will start the thread passing the name of the file that raised the event
.....
Thread t = new Thread(ProcessFiles);
t.Start(e.FullPath);
.....
the ProcessFiles receive the argument with the name of the file to process...
public void ProcessFiles(object argument)
{
string fullFileName = (string)argument;
GetCruiseLineShipName(fullFileName, ref cruiseLine, ref shipName);
using (StreamReader sr = new StreamReader(File.Open(fullFileName, ....))
.....
}
I was wondering if it is possible to retreive from Windows a list of the applications installed INCLUDING their GUID and Upgrade GUID. I am having problems getting my upgrade to work for one of my programs, and need to check these values for the old version of the program. Thanks for the help!
You can use MSI api functions to enumerate all installed products and to query their properties. If you replace MsiGetProductInfo with MsiGetProductInfoEx you will be able to query additional information such as the installation context or user SID associated for an installation.
However, this does not allow you to enumerate the UpgradeCode. As far as I know MSI doesn't keep a record associating a ProductCode with an UpgradeCode; only the reverse mapping is available and you can enumerate the products related to an UpgradeCode using the MsiEnumRelatedProducts function.
Below you will find sample code which enumerates the installed or advertised products and their ProductCode using C#:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
class Program
{
[DllImport("msi.dll", CharSet = CharSet.Unicode)]
static extern Int32 MsiGetProductInfo(string product, string property,
[Out] StringBuilder valueBuf, ref Int32 len);
[DllImport("msi.dll", SetLastError = true)]
static extern int MsiEnumProducts(int iProductIndex,
StringBuilder lpProductBuf);
static void Main(string[] args)
{
StringBuilder sbProductCode = new StringBuilder(39);
int iIdx = 0;
while (MsiEnumProducts(iIdx++, sbProductCode) == 0)
{
Int32 productNameLen = 512;
StringBuilder sbProductName = new StringBuilder(productNameLen);
MsiGetProductInfo(sbProductCode.ToString(),
"ProductName", sbProductName, ref productNameLen);
Console.WriteLine("Product: {0}\t{1}", sbProductName, sbProductCode);
}
}
}
Update
If you still have the MSI installer of the previous version you can simply open the file using Orca and search for the UpgradeCode.
I am setting a Session variable in an HttpHandler, and then getting its value in the Page_load event of an ASPX page. I'm setting it using
public void ProcessRequest(HttpContext context)
{
HttpPostedFile file = context.Request.Files["Filedata"];
context.Session["WorkingImage"] = file.FileName;
}
(And before someone suggests that I check the validity of file.FileName, this same problem occurs if I hard-code a test string in there.) It's working just fine in IE, but in Firefox the Session Variable is not found, getting the "Object reference not set to an instance of an object" error in the following code:
protected void Page_Load(object sender, EventArgs e)
{
string loc = Session["WorkingImage"].ToString();
}
Has anyone encountered this problem - and hopefully come up with a means for passing the session variable?
This is for an HTTPHandler? If this by some chance has something to do with Flash, and Flash is making the request, you will be very interested in reading about the Flash Cookie Bug. Basically, Flash only forwards IE cookies.
The easist fix is to call correctCookie at Application_BeginRequest in your Global.asax and put the SessionId in the querystring of the Flash request.
Public Shared Sub correctCookie()
Try
Dim session_cookie_name As String = "ASP.NET_SESSIONID"
Dim session_value As String = HttpContext.Current.Request.QueryString("sid")
If session_value IsNot Nothing Then
UpdateCookie(session_cookie_name, session_value)
End If
Catch ex As Exception
End Try
End Sub
Private Shared Sub UpdateCookie(ByVal cookie_name As String, ByVal cookie_value As String)
Dim cookie As HttpCookie = HttpContext.Current.Request.Cookies.[Get](cookie_name)
If cookie Is Nothing Then
Dim cookie1 As New HttpCookie(cookie_name, cookie_value)
HttpContext.Current.Response.Cookies.Add(cookie1)
Else
cookie.Value = cookie_value
HttpContext.Current.Request.Cookies.[Set](cookie)
End If
End Sub