Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

SignTool Error: File not found

1,642 views
Skip to first unread message

Coderanger

unread,
Sep 2, 2006, 3:51:40 PM9/2/06
to
I am using the signtool command to sign a setup file. Now, our setup
file is unique to each download and created dynamically so I have
created a COM object to sign the files from within our ASP script.

Now, the code I have written all works when debugging, it works using a
C interface, it works using VBScript (Wscript.exe) but when I put it in
an ASP page and call it, I get "SignTool Error: File not found:
D:\MyPFX.pfx".

I am using a piped "CreateProcess" within my COM object to do this
signing, I also trace/output the commands I am sending to the process
and if i copy this exact text into a command prompt it also works.

So I am a bit stuck with this really, I cant seem to get it working no
matter what i try. The PFX file exists, it exists in the fully
qualified path i am sending to signtool, it finds signtool.exe in the
same path, so why cant it find the PFX file.

Does anyone have any ideas whatsoever, please??

Mitch Gallant

unread,
Sep 2, 2006, 5:47:18 PM9/2/06
to
This *could* be an ACL problem of accessing the PFX file from asp.
Is that pfx file enabled for read access for the IUSR_machinename
account?

See also:
http://www.jensign.com/JavaScience/aspcapicom

- Mitch Gallant
MVP Security


"Coderanger" <da...@coderanger.com> wrote in message
news:1157226700.6...@74g2000cwt.googlegroups.com...

Coderanger

unread,
Sep 3, 2006, 3:52:32 AM9/3/06
to
> This *could* be an ACL problem of accessing the PFX file from asp.
> Is that pfx file enabled for read access for the IUSR_machinename
> account?
>
> See also:
> http://www.jensign.com/JavaScience/aspcapicom
I did think of that, but the folder that contains the PFX file has Full
Control for the "Everyone" user and all child objects inherit this ...
I also tried specifically adding IUSR/IWAM/Network/System and various
other users to the parent folder and giving them all Full Control which
again is inherited.

Still didnt help, but I will take a moment to look at CAPICOM. I did
see some other object like this, but it was only for signing scripts;
didnt see CAPICOM before. Thanks, I will report back if it helps.

Mitch Gallant

unread,
Sep 3, 2006, 9:00:10 AM9/3/06
to
Haver you tried simple things like invoking a dir command from your asp to
see the pfx file listed and its file size etc.?
Also, how are you using the pfx file from asp? I assum you aren't triing to
invoke the UI for the password of the pfx?
- Mitch

"Coderanger" <da...@coderanger.com> wrote in message

news:1157269952.2...@p79g2000cwp.googlegroups.com...

Coderanger

unread,
Sep 3, 2006, 12:29:30 PM9/3/06
to
The winhttpcertcfg option didnt work. I will look into the CAPI stuff
now.

I will try your "dir", but I almost positive that it will be fine.

I am invoking the signtool using a piped CreateProcess. I am using the
same command and parameters which work in a command shell (basically I
trace the information out and copy it into a shell and it works) so I
know all the parameters are right, that the paths are all okay and
surrounded by quotes and no GUI is displayed as I pass the password as
an argument to signtool.

Coderanger

unread,
Sep 3, 2006, 5:50:29 PM9/3/06
to
Right I got it working in the end, I used the CAPICOM com object to
sign my file:

#import "c:\windows\system32\capicom.dll"

CAPICOM::ISigner2Ptr ptrSigner;
HRESULT hr = ptrSigner.CreateInstance( __uuidof( CAPICOM::Signer ) );
if( FAILED( hr ) )
{
return false;
}

CAPICOM::ISignedCodePtr ptrSignCode;
HRESULT hr = ptrSignCode.CreateInstance( __uuidof( CAPICOM::SignedCode
) );
if( FAILED( hr ) )
{
return false;
}


_bstr_t bstrPFXFile( "c:\my.pfx" );
_bstr_t bstrPassword( "mypassword" );
ptrSigner->Load( bstrPFXFile, bstrPassword );

_bstr_t bstrFileName( "c:\mysetup.exe" );
ptrSignCode->FileName = bstrFileName;

_bstr_t bstr( "A Great Product" );
ptrSignCode->Description = bstr;

_bstr_t bstr( "http://www.coderanger.com" );
ptrSignCode->DescriptionURL = bstr;


HRESULT hr = ptrSignCode->Sign( (CAPICOM::ISigner2Ptr)ptrSigner );
if( FAILED( hr ) )
{
printf( "CapiCom Error: ptrSignCode->Sign() failed with code %#x at
line %d", hr, __LINE__ );
return false;
}

printf("hurrah");
return true;


But I also had to set the script that uses my COM object which does the
signing (amongst other stuff), to use a local user account and not IUSR
under the "Anonymous Account" group of "File Security" in IIS.

I hope this helps others. Thanks for all your help and pointers, I
couldnt have done it without your help.

Heres a bit of VBScript that does same thing:
Dim Signer, SignedCode
Set Signer = WScript.CreateObject("CAPICOM.Signer.2")
call Signer.Load( "c:\MyPFX.pfx", "mypassword" )

Set SignedCode = WScript.CreateObject("CAPICOM.SignedCode")
SignedCode.FileName = "c:\setup.exe"

call SignedCode.Sign( Signer )

Mitch Gallant

unread,
Sep 4, 2006, 12:05:59 AM9/4/06
to

"Coderanger" <da...@coderanger.com> wrote in message
news:1157320229....@m79g2000cwm.googlegroups.com...
-- snip

> But I also had to set the script that uses my COM object which does the
> signing (amongst other stuff), to use a local user account and not IUSR
> under the "Anonymous Account" group of "File Security" in IIS.
>

hmmm, I did something very similar (asp/CAPICOM (VBScript) dynamic PE
code-signing, but instead of using a pfx for server signing-key access, the
key was first imported into LM / MY store and the private key file was ACL'd
ONLY with IUSR_<machinename> account for read access and there was no
problem with asp signing. Not sure why you need more in your case.
Some basic code including adding custom "descriptive information" into the
dynamically signed exe and also timestamping it:

Const CAPICOM_LOCAL_MACHINE_STORE = 1
Const CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME = 1
Const SubjectName = "MyCNSubstring"

Set Store = Server.CreateObject("CAPICOM.Store")
Store.Open CAPICOM_LOCAL_MACHINE_STORE, "MY" ,0 'Open LocalMachine store
for read
Set Certificates =
Store.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, SubjectName)

Set Signer = Server.CreateObject("CAPICOM.Signer")
Signer.Certificate = Certificates(1)
Signer.Options = 0

Set oSigcode = CreateObject("CAPICOM.SignedCode")
oSigcode.FileName = FileToSign
oSigcode.Description = describeexe

oSigcode.Sign Signer

' ------- Timestamp the signed file ------------
oSigCode.Timestamp TIMESTAMPURL

Good to hear you got it working.

- Mitch


Coderanger

unread,
Sep 4, 2006, 9:35:03 AM9/4/06
to
I put all this on our live Server2003 machine and my solution didnt
work.

So I rewrote the COM to use the Store like you suggest, again all works
locally, dont work on the live machine.

I cant even get the bloomin "winhttpcertcfg" tool to work, it just
prints out the copyright and then nothing else when i try and import
the PFX file into the LOCAL_MACHINE\My store

If I try and list anything using winhttpcertcfg I get a stupid "Unable
to find or obtain a context for requested certificate" error.

Any ideas??

Mitch Gallant

unread,
Sep 4, 2006, 10:16:05 AM9/4/06
to
I've only tested this in a much simpler environment:
XP Pro sp2 | IIS 5 server (super clean config)
Possibly Server2003 is more locked down ..

When you import the signing key into LM\MY store you need to ACL read access
for IUSR_machinename to the PRIVATE key file.
That file, created when you import your pfx, can be found manually in this
folder (for XP Pro):
C:\Documents and Settings\All Users\Application
Data\Microsoft\Crypto\RSA\MachineKeys
If multiple keys in there, just find the date correspondingto the time you
imported your pfx.
Alternately, there is a very easy to use vbs tool with CAPICOM 2
distribution which makes this ACLing procedure painless:
C:\capicom\CAPICOM 2.1.0.1\samples\vbs\CSetKeyPerm.vbs
I have used this tool a number of times. Browse the vbs source script to
see how the various command-line options work before using it!

I don't use the winhttpcertcfg tool .. is it still supported?

- Mitch Gallant

"Coderanger" <da...@coderanger.com> wrote in message

news:1157376903.9...@m79g2000cwm.googlegroups.com...

Coderanger

unread,
Sep 4, 2006, 11:29:13 AM9/4/06
to
winhttpcertcfg was the problem ... stupid useless tool .. it wouldnt
"import" the PFX file, it gave no errors just listed the two lines of
copyright information then nothing!

Basically I had to do this:
Run->mmc.exe
Choose "Add SnapIns"
Select "Certificates"
Select "Local Computer"
Right-click "Personal" store and choose Import
Browse to your PFX file and import it

Now use the command line tool to grant permissions to appropriate
accounts:
winhttpcertcfg -g -c LOCAL_MACHINE\My -a IUSR_MACHINENAME -s
"yourcompanyname"

Then, to verify and list permissions:
winhttpcertcfg -l -c LOCAL_MACHINE\My -s "yourcompanyname"

Then it all works ... hurrah!!

Thanks for your help, we now have a working system.

Mitch Gallant

unread,
Sep 4, 2006, 2:18:57 PM9/4/06
to
Great .. ... that CAPICOM tool i mentioned would do the same thing as
winhttpcertcfg and
is a bit more general.
Yup Certs Snapin with LC is easiest way to import.
Now your signing key is nicely integrated into capi storage :-)
- Mitch

"Coderanger" <da...@coderanger.com> wrote in message

news:1157383753....@p79g2000cwp.googlegroups.com...

Coderanger

unread,
Sep 5, 2006, 10:53:29 AM9/5/06
to
> Great .. ... that CAPICOM tool i mentioned would do the same thing as
> winhttpcertcfg and
> is a bit more general.
> Yup Certs Snapin with LC is easiest way to import.
> Now your signing key is nicely integrated into capi storage :-)
> - Mitch
Sure, but its a bit more work to write a program to set permissions of
an imported key than it is to just run the winhttp tool ... especially
as its only done once.

Now, I have to wait until next year to find out how its all going to
work when I have to renew the certificate, eek!! :-)

Mitch Gallant

unread,
Sep 5, 2006, 11:58:22 AM9/5/06
to

"Coderanger" <da...@coderanger.com> wrote in message
news:1157468009....@i3g2000cwc.googlegroups.com...

>> Great .. ... that CAPICOM tool i mentioned would do the same thing as
>> winhttpcertcfg and
>> is a bit more general.
>> Yup Certs Snapin with LC is easiest way to import.
>> Now your signing key is nicely integrated into capi storage :-)
>> - Mitch
> Sure, but its a bit more work to write a program to set permissions of
> an imported key than it is to just run the winhttp tool ... especially
> as its only done once.
>

Well that CAPICOM *tool* CSetKeyPerm.vbs is already written and is as easy
to use (sort of) as winhttpcertcfg ;-)
- Mitch


0 new messages