int main()

in xsec/tools/templatesign/templatesign.cpp [553:1342]


int main(int argc, char **argv) {

    XSECCryptoKey               * key = NULL;
    DSIGKeyInfoX509             * keyInfoX509 = NULL;
    const char                  * x509SubjectName = NULL;
#if defined (XSEC_HAVE_OPENSSL)
    OpenSSLCryptoX509           * certs[128];
#endif
    int                         certCount = 0;
    int                         paramCount;
    bool                        clearKeyInfo = false;
#if defined(XSEC_HAVE_WINCAPI)
    HCRYPTPROV                  win32DSSCSP = 0;        // Crypto Provider
    HCRYPTPROV                  win32RSACSP = 0;        // Crypto Provider
    bool                        winDssKeyInfo = false;
    bool                        winRsaKeyInfo = false;
    WinCAPICryptoKeyDSA         * winKeyDSA = NULL;
    WinCAPICryptoKeyRSA         * winKeyRSA = NULL;
#endif

    // Initialise the XML system

    try {

        XMLPlatformUtils::Initialize();
#ifdef XSEC_HAVE_XALAN
        XPathEvaluator::initialize();
        XalanTransformer::initialize();
#endif
        XSECPlatformUtils::Initialise();

    }

    catch (const XMLException &e) {

        cerr << "Error during initialisation of Xerces" << endl;
        cerr << "Error Message = : "
             << e.getMessage() << endl;

    }

#if defined (XSEC_HAVE_OPENSSL)
    
    // Initialize OpenSSL
    ERR_load_crypto_strings();
    BIO * bio_err;
    
    if ((bio_err=BIO_new(BIO_s_file())) != NULL)
        BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);

#endif

    if (argc < 2) {

        printUsage();
        exit (1);
    }
    
    paramCount = 1;

    while (paramCount < argc - 1) {

        // Run through all parameters

        if (_stricmp(argv[paramCount], "--x509subjectname") == 0 || _stricmp(argv[paramCount], "-s") == 0) {

            if (paramCount +2 >= argc) {

                printUsage();
                exit(1);
            }

            // Get the subject name

            x509SubjectName = argv[paramCount + 1];
            paramCount += 2;
        }

#if defined (XSEC_HAVE_OPENSSL)

        else if (_stricmp(argv[paramCount], "--dsakey") == 0 || _stricmp(argv[paramCount], "-d") == 0
            || _stricmp(argv[paramCount], "--rsakey") == 0 || _stricmp(argv[paramCount], "-r") == 0
#   if defined(XSEC_OPENSSL_HAVE_EC)
            || _stricmp(argv[paramCount], "--eckey") == 0 || _stricmp(argv[paramCount], "-e") == 0
#   endif
            ) {

            // OpenSSL Key

            if (paramCount + 3 >= argc) {

                printUsage();
                exit (1);

            }

            if (key != 0) {

                cerr << "\nError loading private key - another key already loaded\n\n";
                printUsage();
                exit(1);

            }

            // Load the signing key
            // For now just read a particular file

            BIO * bioKey;
            if ((bioKey = BIO_new(BIO_s_file())) == NULL) {

                cerr << "Error opening private key file\n\n";
                exit (1);

            }

            if (BIO_read_filename(bioKey, argv[paramCount + 1]) <= 0) {

                cerr << "Error opening private key file\n\n";
                exit (1);

            }

            EVP_PKEY * pkey;
            pkey = PEM_read_bio_PrivateKey(bioKey,NULL,NULL,argv[paramCount + 2]);

            if (pkey == NULL) {

                cerr << "Error loading private key\n\n";
                ERR_print_errors(bio_err);
                exit (1);

            }

            if (_stricmp(argv[paramCount], "--dsakey") == 0 || _stricmp(argv[paramCount], "-d") == 0) {

                // Check type is correct

                if (EVP_PKEY_id(pkey) != EVP_PKEY_DSA) {
                    cerr << "DSA Key requested, but OpenSSL loaded something else\n";
                    exit (1);
                }

                // Create the XSEC OpenSSL interface
                key = new OpenSSLCryptoKeyDSA(pkey);
            }
#if defined(XSEC_OPENSSL_HAVE_EC)
            else if (_stricmp(argv[paramCount], "--eckey") == 0 || _stricmp(argv[paramCount], "-e") == 0) {

                // Check type is correct

                if (EVP_PKEY_id(pkey) != EVP_PKEY_EC) {
                    cerr << "EC Key requested, but OpenSSL loaded something else\n";
                    exit (1);
                }

                // Create the XSEC OpenSSL interface
                key = new OpenSSLCryptoKeyEC(pkey);
            }
#endif
            else {
                if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) {
                    cerr << "RSA Key requested, but OpenSSL loaded something else\n";
                    exit (1);
                }
                key = new OpenSSLCryptoKeyRSA(pkey);
            }

            EVP_PKEY_free(pkey);
            BIO_free(bioKey);

            paramCount += 3;
            
        } /* argv[1] = "dsa/rsa/ec" */


        else if (_stricmp(argv[paramCount], "--x509cert") == 0 || _stricmp(argv[paramCount], "-x") == 0) {

            // X509Data keyInfo

            if (paramCount + 2 >= argc) {

                printUsage();
                exit (1);

            }

            // Load the cert.
            // For now just read a particular file

            BIO * bioX509;

            if ((bioX509 = BIO_new(BIO_s_file())) == NULL) {

                cerr << "Error opening file\n\n";
                exit (1);

            }

            if (BIO_read_filename(bioX509, argv[paramCount + 1]) <= 0) {

                cerr << "Error opening X509 Certificate " << argv[paramCount + 1] << "\n\n";
                exit (1);

            }

            X509 * x
                ;
            x = PEM_read_bio_X509_AUX(bioX509,NULL,NULL,NULL);

            if (x == NULL) {

                cerr << "Error loading certificate\n\n";
                ERR_print_errors(bio_err);
                exit (1);

            }

            // Create the XSEC OpenSSL interface - used only to translate to Base64

            certs[certCount++] = new OpenSSLCryptoX509(x);
            X509_free(x);
            BIO_free(bioX509);

            paramCount += 2;
            
        } /* argv[1] = "--x509cert" */
        
        else 
#endif
        if (_stricmp(argv[paramCount], "--hmackey") == 0 || _stricmp(argv[paramCount], "-h") == 0) {
            XSECCryptoKeyHMAC* hmacKey = XSECPlatformUtils::g_cryptoProvider->keyHMAC();
            hmacKey->setKey((unsigned char *) argv[paramCount + 1], (unsigned int) strlen(argv[paramCount + 1]));
            key = hmacKey;
            paramCount += 2;

        }

        else if (_stricmp(argv[paramCount], "--clearkeys") == 0 || _stricmp(argv[paramCount], "-c") == 0) {

            clearKeyInfo = true;
            paramCount += 1;

        }

#if defined (XSEC_HAVE_WINCAPI)
        else if (_stricmp(argv[paramCount], "--windss") == 0 || _stricmp(argv[paramCount], "-wd") == 0) {

            WinCAPICryptoProvider * cp;
            // First set windows as the crypto provider
            cp = new WinCAPICryptoProvider();
            XSECPlatformUtils::SetCryptoProvider(cp);
            
            // Now set the key
            if (!CryptAcquireContext(&win32DSSCSP,
                NULL,
                NULL,
                PROV_DSS,
                0)) {

                cerr << "Error acquiring Crypto context - Attempting to generate new key pair" << endl;
                
                // Attempt to gen a new keyset
                if (!CryptAcquireContext(&win32DSSCSP,
                    NULL,
                    NULL,
                    PROV_DSS,
                    CRYPT_NEWKEYSET)) {
                        cerr << "Error acquiring DSS Crypto Service Provider with new keyset" << endl;
                        return 2;
                }
                else {
                    HCRYPTKEY k;
                    if (!CryptGenKey(win32DSSCSP, AT_SIGNATURE, CRYPT_EXPORTABLE, &k)) {
                        cerr << "Error generating DSS keyset" << endl;
                        return 2;
                    }
                    CryptDestroyKey(k);
                }
            }
            
            winKeyDSA = new WinCAPICryptoKeyDSA(win32DSSCSP, AT_SIGNATURE, true);
            key = winKeyDSA;
            paramCount++;
        }

        else if (_stricmp(argv[paramCount], "--winrsa") == 0 || _stricmp(argv[paramCount], "-wr") == 0) {
            WinCAPICryptoProvider * cp;
            cp = new WinCAPICryptoProvider();
            XSECPlatformUtils::SetCryptoProvider(cp);

            if (!CryptAcquireContext(&win32RSACSP,
                NULL,
                NULL,
                PROV_RSA_FULL,
                0)) {

                cerr << "Error acquiring Crypto context - Attempting to generate new RSA key pair" << endl;
                
                // Attempt to gen a new keyset
                if (!CryptAcquireContext(&win32RSACSP,
                    NULL,
                    NULL,
                    PROV_RSA_FULL,
                    CRYPT_NEWKEYSET)) {
                        cerr << "Error acquiring RSA Crypto Service Provider with new keyset" << endl;
                        return 2;
                }
                else {
                    HCRYPTKEY k;
                    if (!CryptGenKey(win32RSACSP, AT_SIGNATURE, CRYPT_EXPORTABLE, &k)) {
                        cerr << "Error generating RSA keyset" << endl;
                        return 2;
                    }
                    CryptDestroyKey(k);
                }
            }

            winKeyRSA = new WinCAPICryptoKeyRSA(win32RSACSP, AT_SIGNATURE, true);
            key = winKeyRSA;
            paramCount++;
        }

        else if (_stricmp(argv[paramCount], "--winhmac") == 0 || _stricmp(argv[paramCount], "-wh") == 0) {

            WinCAPICryptoProvider * cp;
            // Obtain default PROV_RSA, with default user key container
            // Note we open in VERIFYCONTEXT as we do not require a assymetric key pair
            if (!CryptAcquireContext(&win32RSACSP,
                NULL,
                NULL,
                PROV_RSA_FULL,
                CRYPT_VERIFYCONTEXT)) {
                    cerr << "Error acquiring RSA Crypto Service Provider" << endl;
                    return 2;
            }
            cp = new WinCAPICryptoProvider();
            XSECPlatformUtils::SetCryptoProvider(cp);

            paramCount++;
            HCRYPTKEY k;
            HCRYPTHASH h;
            BOOL fResult = CryptCreateHash(
                win32RSACSP,
                CALG_SHA,
                0,
                0,
                &h);

            if (fResult == 0) {
                cerr << "Error creating hash to create windows hmac key from password" << endl;
                return 2;
            }
            fResult = CryptHashData(
                h,
                (unsigned char *) argv[paramCount],
                (DWORD) strlen(argv[paramCount]),
                0);
            
            if (fResult == 0) {
                cerr << "Error hashing password to create windows hmac key" << endl;
                return 2;
            }

            // Now create a key
            fResult = CryptDeriveKey(
                win32RSACSP,
                CALG_RC2,
                h,
                CRYPT_EXPORTABLE,
                &k);

            if (fResult == 0) {
                cerr << "Error deriving key from hash value" << endl;
                return 2;
            }

            // Wrap in a WinCAPI object
            WinCAPICryptoKeyHMAC * hk;
            hk = new WinCAPICryptoKeyHMAC(win32RSACSP);
            hk->setWinKey(k); 

            key = hk;

            CryptDestroyHash(h);
            paramCount++;

        }

        else if (_stricmp(argv[paramCount], "--windsskeyinfo") == 0 || _stricmp(argv[paramCount], "-wdi") == 0) {
            winDssKeyInfo = true;
            paramCount++;
        }

        else if (_stricmp(argv[paramCount], "--winrsakeyinfo") == 0 || _stricmp(argv[paramCount], "-wri") == 0) {
            winRsaKeyInfo = true;
            paramCount++;
        }

        // Need to find a better way to check this
        // If CryptAcquireCertificatePrivateKey is not defined in the included
        // version of wincapi.h, CRYPT_ACQUIRE_CACHE_FLAG will not be set

#if defined (CRYPT_ACQUIRE_CACHE_FLAG)
        
        // Code provided by Milan Tomic

        //Please note that this example below use CryptAcquireCertificatePrivateKey() function
        //which is not declared in wincrypt.h that ships with VC++ 6. If you would like to run
        //this example you'll need to replace your old wincrypt.h and crypt32.lib with new versions.
        //This example below is compatible with Windows 98/IE 5 and above OS/IE versions.

        else if (_stricmp(argv[paramCount], "--wincer") == 0 || _stricmp(argv[paramCount], "-wc") == 0) {
            WinCAPICryptoProvider * cp;
            PCCERT_CONTEXT          pSignerCert = NULL;
            DWORD                   dwKeySpec;
            HCERTSTORE              hStoreHandle;
            #define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

            // Obtain default PROV_DSS with default user key container
            if (!CryptAcquireContext(&win32DSSCSP,
                NULL,
                NULL,
                PROV_DSS,
                0)) {
                    cerr << "Error acquiring DSS Crypto Service Provider" << endl;
                    return 2;
            }//*/

            // Open 'Personal' certificate store 
            if (!(hStoreHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM,
                0,
                NULL,
                CERT_SYSTEM_STORE_CURRENT_USER,
                L"MY"))) {
                    cerr << "Error opening 'Personal' store." << endl;
                    return 2;
            }

            // Find desired cerificate
            if (!(pSignerCert = CertFindCertificateInStore(hStoreHandle,
                MY_ENCODING_TYPE,
                0,
                CERT_FIND_SUBJECT_STR_A,
                argv[paramCount+1],
                NULL))) {
                    cerr << "Can't find '" << argv[paramCount+1] << "' certificate in 'Personal' store." << endl;
                    return 2;
            }

            // Now get certificate's private key
            if (!CryptAcquireCertificatePrivateKey(pSignerCert,
                0,
                NULL,
                &win32RSACSP,
                &dwKeySpec,
                NULL)) {
                    cerr << "Can't acquire private key of '" << argv[paramCount+1] << "' certificate." << endl;
                    exit(1);
            }

            cp = new WinCAPICryptoProvider();
            XSECPlatformUtils::SetCryptoProvider(cp);

            HCRYPTKEY k;
            BOOL fResult = CryptGetUserKey(
                win32RSACSP,
                dwKeySpec,
                &k);

            if (!fResult || k == 0) {
                cerr << "Error obtaining default user (AT_SIGNATURE or AT_KEYEXCHANGE) key from windows RSA provider.\n";
                exit(1);
            };

            winKeyRSA = new WinCAPICryptoKeyRSA(win32RSACSP, k);
            key = winKeyRSA;
            paramCount += 2;

            CertFreeCertificateContext(pSignerCert);
            CertCloseStore(hStoreHandle, 0);
        }

#endif /* CRYPT_ACQUIRE_CACHE_FLAG */

#endif /* XSEC_HAVE_WINCAPI */

        else {

            printUsage();
            exit(1);

        }

    }

    // Create and set up the parser

    XercesDOMParser * parser = new XercesDOMParser;
    
    parser->setDoNamespaces(true);
    parser->setCreateEntityReferenceNodes(true);

    // Now parse out file

    bool errorsOccured = false;
    XMLSize_t errorCount = 0;
    try
    {
        parser->parse(argv[argc - 1]);
        errorCount = parser->getErrorCount();
        if (errorCount > 0)
            errorsOccured = true;
    }

    catch (const XMLException& e)
    {
        cerr << "An error occurred during parsing\n   Message: "
             << e.getMessage() << endl;
        errorsOccured = true;
    }


    catch (const DOMException& e)
    {
       cerr << "A DOM error occurred during parsing\n   DOMException code: "
             << e.code << endl;
        errorsOccured = true;
    }

    if (errorsOccured) {

        cout << "Errors during parse" << endl;
        exit (1);

    }

    /*

        Now that we have the parsed file, get the DOM document and start looking at it

    */
    
    DOMNode *doc;       // The document that we parsed

    doc = parser->getDocument();
    DOMDocument *theDOM = parser->getDocument();

    // Find the signature node
    
    DOMNode *sigNode = findDSIGNode(doc, "Signature");

    // Create the signature checker

    if (sigNode == 0) {

        cerr << "Could not find <Signature> node in " << argv[argc-1] << endl;
        exit(1);
    }


    XSECProvider * prov = new XSECProvider;
    DSIGSignature * sig = prov->newSignatureFromDOM(theDOM, sigNode);
     
    // Map out base path of the file
    char * filename=argv[argc-1];
#if XSEC_HAVE_GETCWD_DYN
    char *path = getcwd(NULL, 0);
    char *baseURI = (char*)malloc(strlen(path) + 8 + 1 + strlen(filename) + 1);
#else
    char path[PATH_MAX];
    char baseURI[(PATH_MAX * 2) + 10];
    getcwd(path, PATH_MAX);
#endif
    strcpy(baseURI, "file:///");        

    // Ugly and nasty but quick
    if (filename[0] != '\\' && filename[0] != '/' && filename[1] != ':') {
        strcat(baseURI, path);
        strcat(baseURI, "/");
    } else if (path[1] == ':') {
        path[2] = '\0';
        strcat(baseURI, path);
    }

    strcat(baseURI, filename);

    // Find any ':' and "\" characters
    int lastSlash = 0;
    for (unsigned int i = 8; i < strlen(baseURI); ++i) {
        if (baseURI[i] == '\\') {
            lastSlash = i;
            baseURI[i] = '/';
        }
        else if (baseURI[i] == '/')
            lastSlash = i;
    }

    // The last "\\" must prefix the filename
    baseURI[lastSlash + 1] = '\0';

    sig->getURIResolver()->setBaseURI(MAKE_UNICODE_STRING(baseURI));
#if XSEC_HAVE_GETCWD_DYN
    free(path);
    free(baseURI);
#endif

    try {
        sig->load();
        if (clearKeyInfo == true)
            sig->clearKeyInfo();
        if (key != NULL)
            sig->setSigningKey(key);
        sig->sign();

        // Add any KeyInfo elements

#if defined(XSEC_HAVE_WINCAPI)

        if (winDssKeyInfo == true && winKeyDSA != NULL) {
            char pBuf[1024];
            char qBuf[1024];
            char gBuf[1024];
            char yBuf[1024];

            unsigned int i;
            i = winKeyDSA->getPBase64BigNums((char *) pBuf, 1024);
            pBuf[i] = '\0';
            i = winKeyDSA->getQBase64BigNums((char *) qBuf, 1024);
            qBuf[i] = '\0';
            i = winKeyDSA->getGBase64BigNums((char *) gBuf, 1024);
            gBuf[i] = '\0';
            i = winKeyDSA->getYBase64BigNums((char *) yBuf, 1024);
            yBuf[i] = '\0';

            sig->clearKeyInfo();
            sig->appendDSAKeyValue(
                MAKE_UNICODE_STRING(pBuf),
                MAKE_UNICODE_STRING(qBuf),
                MAKE_UNICODE_STRING(gBuf),
                MAKE_UNICODE_STRING(yBuf));
        }

        if (winRsaKeyInfo == true && winKeyRSA != NULL) {
            char eBuf[1024];
            char mBuf[1024];

            unsigned int i;
            i = winKeyRSA->getExponentBase64BigNums((char *) eBuf, 1024);
            eBuf[i] = '\0';
            i = winKeyRSA->getModulusBase64BigNums((char *) mBuf, 1024);
            mBuf[i] = '\0';

            sig->clearKeyInfo();
            sig->appendRSAKeyValue(
                MAKE_UNICODE_STRING(mBuf),
                MAKE_UNICODE_STRING(eBuf));
        }

#endif
#if defined (XSEC_HAVE_OPENSSL)
        if (certCount > 0) {

            int i;
            // Have some certificates - see if there is already an X509 list
            DSIGKeyInfoList * kiList = sig->getKeyInfoList();
            int kiSize = (int) kiList->getSize();

            for (i = 0; i < kiSize; ++i) {

                if (kiList->item(i)->getKeyInfoType() == DSIGKeyInfo::KEYINFO_X509) {
                    keyInfoX509 = (DSIGKeyInfoX509 *) kiList->item(i);
                    break;
                }
            }

            if (keyInfoX509 == 0) {

                // Not found - need to create
                keyInfoX509 = sig->appendX509Data();

            }

            for (i = 0; i < certCount; ++i) {

                keyInfoX509->appendX509Certificate(certs[i]->getDEREncodingSB().sbStrToXMLCh());

            }

        } /* certCount > 0 */
#endif
        if (x509SubjectName != NULL) {

            int i;
            // Have some certificates - see if there is already an X509 list
            DSIGKeyInfoList * kiList = sig->getKeyInfoList();
            int kiSize = (int) kiList->getSize();

            for (i = 0; i < kiSize; ++i) {

                if (kiList->item(i)->getKeyInfoType() == DSIGKeyInfo::KEYINFO_X509) {
                    keyInfoX509 = (DSIGKeyInfoX509 *) kiList->item(i);
                    break;
                }
            }

            if (keyInfoX509 == 0) {

                // Not found - need to create
                keyInfoX509 = sig->appendX509Data();

            }

            keyInfoX509->setX509SubjectName(MAKE_UNICODE_STRING(x509SubjectName));

        } /* certCount > 0 */
    }

    catch (const XSECException &e) {
        char * m = XMLString::transcode(e.getMsg());
        cerr << "An error occurred during signing operation\n   Message: "
        << m << endl;
        XSEC_RELEASE_XMLCH(m);
        errorsOccured = true;
        exit (1);
    }

    catch (const XSECCryptoException &e) {
        cerr << "A cryptographic error occurred during signature operation\n   Message: "
        << e.getMsg() << endl;
        errorsOccured = true;
        exit(1);
    }

    catch (const NetAccessorException&) {
        cerr << "A network error occurred during signing operation\n" << endl;
        errorsOccured = true;
        exit(1);
    }

    // Print out the result

    DOMPrintFormatTarget* formatTarget = new DOMPrintFormatTarget();
    
    const XMLCh* encNameStr = XMLString::transcode("UTF-8");
    DOMNode *aNode = doc->getFirstChild();
    if (aNode->getNodeType() == DOMNode::ENTITY_NODE)
    {
        const XMLCh* aStr = ((DOMEntity *)aNode)->getInputEncoding();
        if (!strEquals(aStr, ""))
        {
            encNameStr = aStr;
        }
    }
    XMLSize_t lent = XMLString::stringLen(encNameStr);
    gEncodingName = new XMLCh[lent + 1];
    XMLString::copyNString(gEncodingName, encNameStr, lent);
    gEncodingName[lent] = 0;

    gFormatter = new XMLFormatter("UTF-8", 0, formatTarget,
                                          XMLFormatter::NoEscapes, gUnRepFlags);

    cout << doc;

    delete [] gEncodingName;
    XMLCh * toRelease = (XMLCh *) encNameStr;
    XSEC_RELEASE_XMLCH(toRelease);
    delete gFormatter;
    delete formatTarget;

#if defined (_WIN32) && defined (XSEC_HAVE_WINCAPI)
    if (win32DSSCSP != 0)
        CryptReleaseContext(win32DSSCSP,0);
    if (win32RSACSP != 0)
        CryptReleaseContext(win32RSACSP,0);
#endif

    prov->releaseSignature(sig);
    delete parser;
    delete prov;

    XSECPlatformUtils::Terminate();
#ifdef XSEC_HAVE_XALAN
    XalanTransformer::terminate();
    XPathEvaluator::terminate();
#endif
    XMLPlatformUtils::Terminate();

    
    return 0;
}