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;
}

Reply via email to