Berin,
Using the latest version of xml-security from CVS - I can clone the X509 cert
using WINCAPI but I get errors during sig->validate() regarding and invalid
signature. I tried the same sequence of code using the OpenSSL providers and
got something very similar.
Using WINCAPI - the message
An error occured in the XML-Security-C Crypto routines
Message: WinCAPI:DSA::VerifyBase64Signature - Expect 40 bytes in a DSA
signature
Using OPENSSL - the message
An error occured in the XML-Security-C Crypto routines
Message: OpenSSL:DSA - Signature Length incorrect
(*) Do these errors relate to the certificte or the signature in the XML
document?
(*) For the OpenSSL test, I exported the key as a BASE64 DER encoded
certificate and manually removed the ----BEGIN CERTIFICATE---- and ----END
CERTIFICATE---- headers. Was this the correct thing to do?
bool WinCAPICryptoKeyDSA::verifyBase64Signature(unsigned char * hashBuf,
unsigned int hashLen, char * base64Signature, unsigned int sigLen)
{
.. hashBuf= [data]
.. hashLen= 20
.. base64Signature
"MCwCFFiTYY7/B+tYizrqccMZJKVQC6RyAhQUoVXtXfNUVEFZlaE3USajTEqUzQ=="
.. sigLen= 64
b64.decodeInit();
rawSigLen = b64.decode((unsigned char *) base64Signature, sigLen, rawSig,
sigLen);
rawSigLen += b64.decodeFinish(&rawSig[rawSigLen], sigLen - rawSigLen);
.. rawSigLen = 46
if (rawSigLen != 40)
{
throw XSECCryptoException(XSECCryptoException::DSAError,
"WinCAPI:DSA::VerifyBase64Signature - Expect 40 bytes in a DSA
signature");
}
}
//
// validate.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "IOStreamOutputter.hpp"
#define USE_WINCAPI
// XML-Security-C (XSEC)
#pragma comment (lib, "crypt32.lib")
#pragma comment (lib, "xerces-c_2D.lib")
#pragma comment (lib, "xsec_1D.lib")
#include <xsec/framework/XSECProvider.hpp>
#include <xsec/dsig/DSIGReference.hpp>
#ifdef USE_WINCAPI
#include <xsec/enc/WinCAPI/WinCAPICryptoKeyHMAC.hpp>
#include <xsec/enc/WinCAPI/WinCAPICryptoProvider.hpp>
#include <xsec/enc/WinCAPI/WinCAPICryptoX509.hpp>
#endif
#ifdef USE_OPENSSL
#include <xsec/enc/OpenSSL/OpenSSLCryptoKeyHMAC.hpp>
#include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
#include <xsec/enc/XSECCryptoException.hpp>
#endif // USE_OPENSSL
#include <xsec/framework/XSECException.hpp>
#include <xsec/enc/XSECCryptoException.hpp>
// Xerces
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#if defined(_WIN32)
# include <xsec/utils/winutils/XSECURIResolverGenericWin32.hpp>
#else
# include <xsec/utils/unixutils/XSECURIResolverGenericUnix.hpp>
#endif
XERCES_CPP_NAMESPACE_USE
TCHAR *docToValidate = 0x00;
#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"MYSIGNER"
#define CERT_STORE_NAME L"MY"
void ReadFile(TCHAR *fileName, TCHAR **chars, DWORD *len /* in TCHARS */)
{
DWORD bytesRead = 0;
HANDLE hfp = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
*len = GetFileSize(hfp, NULL);
*len /= sizeof(TCHAR); // convert length from bytes to TCHAR's
*chars = (TCHAR *)malloc(*len * sizeof(TCHAR)); // dont mul by sizeof(TCHAR)
ReadFile(hfp, (LPVOID)*chars, *len * sizeof(TCHAR), &bytesRead, NULL);
CloseHandle(hfp);
}
int main (int argc, char **argv) {
try
{
XMLPlatformUtils::Initialize();
XSECPlatformUtils::Initialise();
}
catch (const XMLException &e)
{
cerr << "Error during initialisation of Xerces" << endl;
cerr << "Error Message = : " << e.getMessage() << endl;
}
// Use xerces to parse the document
XercesDOMParser * parser = new XercesDOMParser;
parser->setDoNamespaces(true);
parser->setCreateEntityReferenceNodes(true);
parser->setDoSchema(true);
// Create an input source
DWORD len = 0;
ReadFile(_T("c:\\apache\\signedxml\\nocert.xml"), &docToValidate, &len);
MemBufInputSource* memIS = new MemBufInputSource ((const XMLByte*)
docToValidate, (unsigned int) len, "XSECMem");
parser->parse(*memIS);
int errorCount = parser->getErrorCount();
if (errorCount > 0) {
cerr << "Error parsing input document\n";
exit (1);
}
DOMDocument *doc = parser->getDocument();
docSetup(doc);
// Now create a signature object to validate the document
XSECProvider prov;
DSIGSignature * sig = prov.newSignatureFromDOM(doc);
// Register defined attribute name
sig->registerIdAttributeName(MAKE_UNICODE_STRING("ID"));
sig->registerIdAttributeNameNS(MAKE_UNICODE_STRING(IDATTRIBUTENS),
MAKE_UNICODE_STRING(IDATTRIBUTENAME));
try
{
#ifdef USE_WINCAPI
HCERTSTORE certStore = NULL;
PCCERT_CONTEXT certContext = NULL;
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. -- this certificate must have access to the
signer's private key.
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);
}
WinCAPICryptoProvider * cp = new WinCAPICryptoProvider(NULL, NULL,
CRYPT_MACHINE_KEYSET);
XSECPlatformUtils::SetCryptoProvider(cp);
WinCAPICryptoX509 * x509 = new WinCAPICryptoX509(certContext,
cp->getProviderRSA(), cp->getProviderDSS());
#endif // USE_WINCAPI
#ifdef USE_OPENSSL
OpenSSLCryptoX509 * x509 = new OpenSSLCryptoX509();
TCHAR *b64;
DWORD b64Len;
ReadFile(_T("c:\\apache\\signedxml\\nocert.cer"), &b64, &b64Len);
x509->loadX509Base64Bin(b64, (unsigned int) b64Len);
#endif // USE_OPENSSL
// in my XML file i have no keyinfo
sig->load();
sig->setSigningKey(x509->clonePublicKey());
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);
}
// Clean up
delete memIS;
delete parser;
return 0;
}