Environment :-
XML-Security-C - CVS version 17/05/05
XALAN-1.7.0 and XERCES-2.5.0
Compiler VC7 (2003)
#define HAVE_OPENSSL 0
#define HAVE_WINCAPI 1
#define USING_XALAN
I am trying to validate a SOAP response signed using the Verisign TSIK toolkit.
The XML-SOAP response has a detached public key which I have installed into the "current user" store.
There is no "KeyInfo" or "Object" in my XML document but this seems to be
acceptable to DSIGSignature::load();
I don't seem to be able to verify the public key via an WinCAPICryptoX509 using
the WinCAPICryptoX509(PCCERT_CONTEXT) constructor - It loads the key correctly
but does not set up the DSA/RSA provider handles which are needed later on
during processing.
Using the mscrypto API - I find the certificate context and create a X509
certificate with it.
WinCAPICryptoX509 * x509 = new WinCAPICryptoX509(certContext);
sig->setSigningKey(x509->clonePublicKey()); // FAILS HERE....
However WinCAPICryptoX509::clonePublicKey() fails due to the fact that WinCAPICryptoX509::m_pDSS has not been set. The only way I seem able to set WinCAPICryptoX509::m_pDSS is via the constructor WinCAPICryptoX509::WinCAPICryptoX509(HCRYPTPROV provRSA, HCRYPTPROV provDSS) but if I do this I am then unable to set
WinCAPICryptoX509::mp_certContext certificate context handle.
(*) Is there a call similar to WinCAPICryptoX509::SetDSAProvider() ?
(*) As an aside the MSDN documentation for CryptImportPublicKeyInfo() states that it
"is always acceptable" to use X509_ASN_ENCODING | PKCS_7_ASN_ENCODING for the
DWORD dwCertEncodingType parameter - [is this relevant?]
To generate a DSS crypto provider handle I am using
WinCAPICryptoProvider * cp = new WinCAPICryptoProvider(NULL, NULL,
CRYPT_MACHINE_KEYSET);
XSECPlatformUtils::SetCryptoProvider(cp);
(*) Would this handle be the correct one to send to
WinCAPICryptoX509::SetDSAProvider() if it existed ie
WinCAPICryptoX509::SetDSAProvider(cp->getProviderDSS());
I have also tried
WinCAPICryptoProvider *cp = new WinCAPICryptoProvider(NULL, NULL, CRYPT_MACHINE_KEYSET);
WinCAPICryptoX509 *x509 = (WinCAPICryptoX509 *)cp->X509();
At this stage there is no way I seem able to set the X509 certificate context eg
x509->mp_certContext = certContext; // no class member fn() exists to allow
me to do this.
(*) If I manually set the value of m_pDSS (via the debugger) inside
WinCAPICryptoX509::clonePublicKey() with a handle derived from calling new
WinCAPICryptoProvider(NULL, NULL, CRYPT_MACHINE_KEYSET).
WinCAPICryptoX509::clonePublicKey() does not fail and "seems" to generate a valid
Key. Calling sig->Verify() however gives me the error message...
WinCAPI:DSA::VerifyBase64Signature - Expect 40 bytes in a DSA signature
-- Does this mean my document is fundementally rubbish ?? Looking at the public
key details I can see.
[Signature Algorithm] sha1DSA
[Public Key] DSA (1024 Bits)
[Thumbprint Algorithm] sha1
Eg...
WinCAPICryptoProvider *cp = new WinCAPICryptoProvider(NULL, NULL,
CRYPT_MACHINE_KEYSET);
// get value of cp->m_provDSS
WinCAPICryptoX509::clonePublicKey()
{
HCRYPTKEY key;
BOOL fResult;
&m_pDSS = 1415288 /* set to valid handle gained by WinCAPICryptoProvider(NULL, NULL, CRYPT_MACHINE_KEYSET); (using debugger)
if(getPublicKeyType() == XSECCryptoKey::KEY_DSA_PUBLIC)
{
fResult= CryptImportPublicKeyInfo(m_pDSS, X509_ASN_ENCODING, &(mp_certContext->pCertInfo->SubjectPublicKeyInfo), &key);
}
}
Can someone verify my steps are correct..
Load the document into DSIGSignature()
CertOpenStore()
certCtxt = CertFindCertificateInStore()
Create X509 from certCtxt
Load the signature inside DSIGSignature()
Set the DSIGSignature signing key to a cloned copy of the public key stored
in X509 (do I have to clone)
verify the DSIGSignature
//
// my source code....based heavily on SimpleValidate.cpp
//
#define IDATTRIBUTENS "http://schemas.xmlsoap.org/ws/2002/07/utility"
#define IDATTRIBUTENAME "Id"
#define MY_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define SIGNER_NAME L"TESTSIGNER"
#define CERT_STORE_NAME L"MY"
int main (int argc, char **argv)
{
//..
//.. Reading and validation code ommitted
//..
// create a signature object to validate the document
XSECProvider prov;
DSIGSignature * sig = prov.newSignatureFromDOM(doc);
sig->registerIdAttributeName(MAKE_UNICODE_STRING("ID"));
// Register defined attribute name
sig->registerIdAttributeNameNS(MAKE_UNICODE_STRING(IDATTRIBUTENS),
MAKE_UNICODE_STRING(IDATTRIBUTENAME));
// using MSCryptoAPI
try
{
HCERTSTORE certStore = NULL;
PCCERT_CONTEXT certContext = NULL;
// open the microsoft certiticate store
certStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL,
CERT_SYSTEM_STORE_CURRENT_USER, CERT_STORE_NAME);
if(certStore == NULL)
{
cout << "Certificate store cannot be opened\n";
exit (1);
}
// find signer's certificate
certContext = CertFindCertificateInStore(certStore, MY_TYPE, 0,
CERT_FIND_SUBJECT_STR, SIGNER_NAME, NULL);
if(certContext == NULL)
{
cout << "unable to find signers certificate\n";
exit (1);
}
// build an x509 certificate from my cert context
WinCAPICryptoX509 * x509 = new WinCAPICryptoX509(certContext);
sig->load();
// no keyinfo in my XML
sig->setSigningKey(x509->clonePublicKey()); // FAILS HERE....
if (sig->verify())
{
cout << "Signature Valid\n";
}
else
{
char * err = XMLString::transcode(sig->getErrMsgs());
cout << "Incorrect Signature\n";
cout << err << endl;
XSEC_RELEASE_XMLCH(err);
}
}
catch (XSECException &e)
{
cerr << "An error occured during a signature load\n Message: " << e.getMsg()
<< endl;
exit(1);
}
catch (XSECCryptoException &e) {
cerr << "An error occured in the XML-Security-C Crypto routines\n Message: " <<
e.getMsg() << endl;
exit(1);
}
return 0;
}