int evaluate()

in xsec/tools/cipher/cipher.cpp [206:829]


int evaluate(int argc, char ** argv) {
    
    char                    * filename = NULL;
    char                    * outfile = NULL;
    unsigned char           * keyStr = NULL;
    bool                    doDecrypt = true;
    bool                    errorsOccured = false;
    bool                    doDecryptElement = false;
    bool                    useInteropResolver = false;
    bool                    encryptFileAsData = false;
    bool                    parseXMLInput = true;
    bool                    doXMLOutput = false;
#ifdef XSEC_XKMS_ENABLED
    bool                    isXKMSKey = false;
#endif
    XSECCryptoKey           * kek = NULL;
    XSECCryptoKey           * key = NULL;
    int                     keyLen = 0;
    const XMLCh*            kekAlg = NULL;
    const XMLCh*            keyAlg = NULL;
    DOMDocument             *doc;
    unsigned char           keyBuf[24];
    XMLFormatTarget         *formatTarget ;

#if defined(_WIN32) && defined (XSEC_HAVE_WINCAPI)
    HCRYPTPROV              win32DSSCSP = 0;        // Crypto Providers
    HCRYPTPROV              win32RSACSP = 0;

    CryptAcquireContext(&win32DSSCSP, NULL, NULL, PROV_DSS, CRYPT_VERIFYCONTEXT);
    CryptAcquireContext(&win32RSACSP, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);

#endif

    if (argc < 2) {

        printUsage();
        return 2;
    }

    // Run through parameters
    int paramCount = 1;

    while (paramCount < argc - 1) {

        if (_stricmp(argv[paramCount], "--decrypt-element") == 0 || _stricmp(argv[paramCount], "-de") == 0) {
            paramCount++;
            doDecrypt = true;
            doDecryptElement = true;
            doXMLOutput = true;
            parseXMLInput = true;
        }
        else if (_stricmp(argv[paramCount], "--interop") == 0 || _stricmp(argv[paramCount], "-i") == 0) {
            // Use the interop key resolver
            useInteropResolver = true;
            paramCount++;
        }
        else if (_stricmp(argv[paramCount], "--encrypt-file") == 0 || _stricmp(argv[paramCount], "-ef") == 0) {
            // Use this file as the input
            doDecrypt = false;
            encryptFileAsData = true;
            doXMLOutput = true;
            parseXMLInput = false;
            paramCount++;
        }
        else if (_stricmp(argv[paramCount], "--encrypt-xml") == 0 || _stricmp(argv[paramCount], "-ex") == 0) {
            // Us this file as an XML input file
            doDecrypt = false;
            encryptFileAsData = false;
            doXMLOutput = true;
            parseXMLInput = true;
            paramCount++;
        }
        else if (_stricmp(argv[paramCount], "--out-file") == 0 || _stricmp(argv[paramCount], "-o") == 0) {
            if (paramCount +2 >= argc) {
                printUsage();
                return 1;
            }
            paramCount++;
            outfile = argv[paramCount];
            paramCount++;
        }
#ifdef XSEC_XKMS_ENABLED
        else if (_stricmp(argv[paramCount], "--xkms") == 0 || _stricmp(argv[paramCount], "-x") == 0) {
            paramCount++;
            isXKMSKey = true;
        }
#endif
#ifdef XSEC_HAVE_WINCAPI
        else if (_stricmp(argv[paramCount], "--wincapi") == 0 || _stricmp(argv[paramCount], "-w") == 0) {
            // Use the interop key resolver
            WinCAPICryptoProvider * cp = new WinCAPICryptoProvider();
            XSECPlatformUtils::SetCryptoProvider(cp);
            paramCount++;
        }
#endif
#ifdef XSEC_HAVE_NSS
        else if (_stricmp(argv[paramCount], "--nss") == 0 || _stricmp(argv[paramCount], "-n") == 0) {
            // NSS Crypto Provider
            NSSCryptoProvider * cp = new NSSCryptoProvider();
            XSECPlatformUtils::SetCryptoProvider(cp);
            paramCount++;
        }
#endif
        else if (_stricmp(argv[paramCount], "--key") == 0 || _stricmp(argv[paramCount], "-k") == 0) {

            // Have a key!
            paramCount++;
            bool isKEK = false;
            XSECCryptoSymmetricKey::SymmetricKeyType loadKeyAs =
                XSECCryptoSymmetricKey::KEY_NONE;

            if (_stricmp(argv[paramCount], "kek") == 0) {
                isKEK = true;
                paramCount++;
                if (paramCount >= argc) {
                    printUsage();
                    return 2;
                }
            }

            if (_stricmp(argv[paramCount], "3DES") == 0 ||
                _stricmp(argv[paramCount], "AES128") == 0 ||
                _stricmp(argv[paramCount], "AES192") == 0 ||
                _stricmp(argv[paramCount], "AES256") == 0 ||
                _stricmp(argv[paramCount], "AES128-GCM") == 0 ||
                _stricmp(argv[paramCount], "AES192-GCM") == 0 ||
                _stricmp(argv[paramCount], "AES256-GCM") == 0) {
                
                if (paramCount +2 >= argc) {
                    printUsage();
                    return 2;
                }

                switch(argv[paramCount][4]) {
                case '\0' :
                    keyLen = 24;
                    loadKeyAs = XSECCryptoSymmetricKey::KEY_3DES_192;
                    keyAlg = DSIGConstants::s_unicodeStrURI3DES_CBC;
                    break;
                case '2' :
                    keyLen = 16;
                    loadKeyAs = XSECCryptoSymmetricKey::KEY_AES_128;
                    if (isKEK) {
                        kekAlg = DSIGConstants::s_unicodeStrURIKW_AES128;
                    }
                    else if (strlen(argv[paramCount]) == 6) {
                        keyAlg = DSIGConstants::s_unicodeStrURIAES128_CBC;
                    }
                    else {
                        keyAlg = DSIGConstants::s_unicodeStrURIAES128_GCM;
                    }
                    break;
                case '9' :
                    keyLen = 24;
                    loadKeyAs = XSECCryptoSymmetricKey::KEY_AES_192;
                    if (isKEK) {
                        kekAlg = DSIGConstants::s_unicodeStrURIKW_AES192;
                    }
                    else if (strlen(argv[paramCount]) == 6) {
                        keyAlg = DSIGConstants::s_unicodeStrURIAES192_CBC;
                    }
                    else {
                        keyAlg = DSIGConstants::s_unicodeStrURIAES192_GCM;
                    }
                    break;
                case '5' :
                    keyLen = 32;
                    loadKeyAs = XSECCryptoSymmetricKey::KEY_AES_256;
                    if (isKEK) {
                        kekAlg = DSIGConstants::s_unicodeStrURIKW_AES256;
                    }
                    else if (strlen(argv[paramCount]) == 6) {
                        keyAlg = DSIGConstants::s_unicodeStrURIAES256_CBC;
                    }
                    else {
                        keyAlg = DSIGConstants::s_unicodeStrURIAES256_GCM;
                    }
                    break;
                }

                paramCount++;
                unsigned char keyStr[64];
                if (strlen(argv[paramCount]) > 64) {
                    cerr << "Key string too long\n";
                    return 2;
                }
                XSECCryptoSymmetricKey * sk = 
                    XSECPlatformUtils::g_cryptoProvider->keySymmetric(loadKeyAs);

#ifdef XSEC_XKMS_ENABLED
                if (isXKMSKey) {
                    unsigned char kbuf[XSEC_MAX_HASH_SIZE];
                    CalculateXKMSKEK((unsigned char *) argv[paramCount], (int) strlen(argv[paramCount]), kbuf, XSEC_MAX_HASH_SIZE);
                    sk->setKey(kbuf, keyLen);
                }
                else {
#endif
                    memset(keyStr, 0, 64);
                    strcpy((char *) keyStr, argv[paramCount]);
                    sk->setKey(keyStr, keyLen);
#ifdef XSEC_XKMS_ENABLED
                }
#endif
                paramCount++;
                if (isKEK)
                    kek = sk;
                else
                    key = sk;
            }


#ifdef XSEC_HAVE_OPENSSL

            else if (_stricmp(argv[paramCount], "RSA") == 0) {
                // RSA private key file

                if (paramCount + 3 >= argc) {

                    printUsage();
                    return 2;

                }

                if (!isKEK) {
                    cerr << "RSA private keys may only be KEKs\n";
                    return 2;
                }

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

                    cerr << "Error opening private key file\n\n";
                    return 1;

                }

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

                    cerr << "Error opening private key file\n\n";
                    return 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";
                    return 1;

                }

                kek = new OpenSSLCryptoKeyRSA(pkey);
                kekAlg = DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1;
                EVP_PKEY_free(pkey);
                BIO_free(bioKey);
                paramCount += 3;
            }

            else if (_stricmp(argv[paramCount], "X509") == 0) {

                // X509 cert used to load an encrypting key

                if (paramCount + 2 >= argc) {

                    printUsage();
                    exit (1);

                }

                if (!isKEK) {
                    cerr << "X509 private keys may only be KEKs\n";
                    return 2;
                }

                // Load the encrypting key
                // 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) {

                    BIO * bio_err;
                    
                    if ((bio_err=BIO_new(BIO_s_file())) != NULL)
                        BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);

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

                }

                // Now load the key
                EVP_PKEY *pkey;

                pkey = X509_get_pubkey(x);
#ifdef XSEC_OPENSSL_HAVE_EVP_PKEY_ID
                if (pkey == NULL || EVP_PKEY_id(pkey) != EVP_PKEY_RSA)
#else
                if (pkey == NULL || pkey->type != EVP_PKEY_RSA)
#endif
                {
                    cerr << "Error extracting RSA key from certificate" << endl;
                }

                kek = new OpenSSLCryptoKeyRSA(pkey);
                kekAlg = DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1;

                // Clean up

                EVP_PKEY_free (pkey);
                X509_free(x);
                BIO_free(bioX509);

                paramCount += 2;
                
            } /* argv[1] = "--x509cert" */
#endif /* XSEC_HAVE_OPENSSL */
            else {
                printUsage();
                return 2;
            }
        }

        else {
            cerr << "Unknown option: " << argv[paramCount] << endl;
            printUsage();
            return 2;
        }
    }

    if (paramCount >= argc) {
        printUsage();
        return 2;
    }

    if (outfile != NULL) {
        formatTarget = new LocalFileFormatTarget(outfile);
    }
    else {
        formatTarget = new StdOutFormatTarget();
    }

    filename = argv[paramCount];

    if (parseXMLInput) {

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

        // Now parse out file

        XMLSize_t errorCount = 0;
        try
        {
            parser->parse(filename);
            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;
            return (2);

        }

        /*

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

        */
        
        doc = parser->adoptDocument();
    }

    else {
        // Create an empty document
        XMLCh tempStr[100];
        XMLString::transcode("Core", tempStr, 99);    
        DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
        doc = impl->createDocument(
            0,                    // root element namespace URI.
            MAKE_UNICODE_STRING("ADoc"),            // root element name
            NULL);// DOMDocumentType());  // document type object (DTD).
    }


    XSECProvider prov;
    XENCCipher * cipher = prov.newCipher(doc);

    if (kek != NULL)
        cipher->setKEK(kek);
    if (key != NULL)
        cipher->setKey(key);

    try {

        if (doDecrypt) {

            if (useInteropResolver == true) {

                // Map out base path of the file
#ifdef 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';

                XMLCh * uriT = XMLString::transcode(baseURI);
#ifdef XSEC_HAVE_GETCWD_DYN
                free(path);
                free(baseURI);
#endif

                XencInteropResolver ires(doc, &(uriT[8]));
                XSEC_RELEASE_XMLCH(uriT);
                cipher->setKeyInfoResolver(&ires);

            }
            // Find the EncryptedData node
            DOMNode * n = findXENCNode(doc, "EncryptedData");

            if (doDecryptElement) {
                while (n != NULL) {

                    // decrypt
                    cipher->decryptElement(static_cast<DOMElement *>(n));

                    // Find the next EncryptedData node
                    n = findXENCNode(doc, "EncryptedData");
                }

            }
            else {
                XSECBinTXFMInputStream * bis = cipher->decryptToBinInputStream(static_cast<DOMElement *>(n));
                Janitor<XSECBinTXFMInputStream> j_bis(bis);
    
                XMLByte buf[1024];          
                XMLSize_t read = bis->readBytes(buf, 1023);
                while (read > 0) {
                    formatTarget->writeChars(buf, read, NULL);
                    read = bis->readBytes(buf, 1023);
                }
            }
        }
        else {

            XENCEncryptedData *xenc = NULL;
            // Encrypting
            if (kek != NULL && key == NULL) {
                XSECPlatformUtils::g_cryptoProvider->getRandom(keyBuf, 24);
                XSECCryptoSymmetricKey * k = 
                    XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_3DES_192);
                k->setKey(keyBuf, 24);
                cipher->setKey(k);
                keyAlg = DSIGConstants::s_unicodeStrURI3DES_CBC;
                keyStr = keyBuf;
                keyLen = 24;
            }

            if (encryptFileAsData) {

                // Create a BinInputStream
                BinFileInputStream * is = new BinFileInputStream(filename, XMLPlatformUtils::fgMemoryManager);
                xenc = cipher->encryptBinInputStream(is, keyAlg);

                // Replace the document element
                DOMElement * elt = doc->getDocumentElement();
                doc->replaceChild(xenc->getElement(), elt);
                elt->release();
            }
            else {
                // Document encryption
                cipher->encryptElement(doc->getDocumentElement(), keyAlg);
            }

            // Do we encrypt a created key?
            if (kek != NULL && xenc != NULL) {
                XENCEncryptedKey *xkey = cipher->encryptKey(keyStr, keyLen, kekAlg);
                // Add to the EncryptedData
                xenc->appendEncryptedKey(xkey);
            }
        }

        if (doXMLOutput) {
            // Output the result

            XMLCh core[] = {
                XERCES_CPP_NAMESPACE_QUALIFIER chLatin_C,
                XERCES_CPP_NAMESPACE_QUALIFIER chLatin_o,
                XERCES_CPP_NAMESPACE_QUALIFIER chLatin_r,
                XERCES_CPP_NAMESPACE_QUALIFIER chLatin_e,
                XERCES_CPP_NAMESPACE_QUALIFIER chNull
            };

            DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(core);

            DOMLSSerializer   *theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer();
            Janitor<DOMLSSerializer> j_theSerializer(theSerializer);
            
            // Get the config so we can set up pretty printing
            DOMConfiguration *dc = theSerializer->getDomConfig();
            dc->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, false);

            // Now create an output object to format to UTF-8
            DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput();
            Janitor<DOMLSOutput> j_theOutput(theOutput);

            theOutput->setEncoding(MAKE_UNICODE_STRING("UTF-8"));
            theOutput->setByteStream(formatTarget);

            theSerializer->write(doc, theOutput);

            cout << endl;

        }
    }

    catch (const XSECException &e) {
        char * msg = XMLString::transcode(e.getMsg());
        cerr << "An error occurred during encryption/decryption operation\n   Message: "
        << msg << endl;
        XSEC_RELEASE_XMLCH(msg);
        errorsOccured = true;
        if (formatTarget != NULL)
            delete formatTarget;
        doc->release();
        return 2;
    }
    catch (const XSECCryptoException &e) {
        cerr << "An error occurred during encryption/decryption operation\n   Message: "
        << e.getMsg() << endl;
        errorsOccured = true;
        if (formatTarget != NULL)
            delete formatTarget;
        doc->release();

#ifdef XSEC_HAVE_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);

        ERR_print_errors(bio_err);
#endif
        return 2;
    }
    
    if (formatTarget != NULL)
        delete formatTarget;

    doc->release();
    return 0;
}