/* * Parse a NSS_P7_EncryptedData - specifically in the context * of a P12 in password privacy mode. (The latter assumption is * to enable us to infer CSSM_X509_ALGORITHM_IDENTIFIER.parameters * format). */ static int encryptedDataParse( const NSS_P7_EncryptedData &edata, P12ParseInfo &pinfo, NSS_P12_PBE_Params *pbep, // optional, RETURNED unsigned depth) // print indent depth { doIndent(depth); printf("version = %u\n", (unsigned)dataToInt(edata.version)); const NSS_P7_EncrContentInfo &ci = edata.contentInfo; doIndent(depth); printf("contentType = %s\n", oidStr(ci.contentType, pinfo.mParser)); /* * Parse the alg ID, safe PBE params for when we do the * key unwrap */ const CSSM_X509_ALGORITHM_IDENTIFIER &algId = ci.encrAlg; if(p12AlgIdParse(algId, pbep, pinfo, depth)) { return 1; } doIndent(depth); printf("encrContent : "); printDataAsHex(&ci.encrContent, 12); return 0; }
static int p12MacParse( const NSS_P12_MacData &macData, P12ParseInfo &pinfo, unsigned depth) // print indent depth { if(p12AlgIdParse(macData.mac.digestAlgorithm, NULL, pinfo, depth)) { return 1; } doIndent(depth); printf("Digest : "); printDataAsHex(&macData.mac.digest, 20); doIndent(depth); printf("Salt : "); printDataAsHex(&macData.macSalt, 16); const CSSM_DATA &iter = macData.iterations; if(iter.Length > 4) { doIndent(depth); printf("***Warning: malformed iteraton length (%u)\n", (unsigned)iter.Length); } unsigned i = dataToInt(iter); doIndent(depth); printf("Iterations = %u\n", i); return 0; }
static int p12Parse( const CSSM_DATA &rawBlob, P12ParseInfo &pinfo, unsigned depth) // print indent depth { NSS_P12_DecodedPFX pfx; memset(&pfx, 0, sizeof(pfx)); if(pinfo.mCoder.decodeItem(rawBlob, NSS_P12_DecodedPFXTemplate, &pfx)) { printf("***Error on top-level decode of NSS_P12_DecodedPFX\n"); return 1; } doIndent(depth); printf("version = %u\n", (unsigned)dataToInt(pfx.version)); NSS_P7_DecodedContentInfo &dci = pfx.authSafe; doIndent(depth); printf("contentType = %s\n", oidStr(dci.contentType, pinfo.mParser)); doIndent(depth); printf("type = %s\n", p7ContentInfoTypeStr(dci.type)); int rtn = 0; if(nssCompareCssmData(&dci.contentType, &CSSMOID_PKCS7_Data)) { doIndent(depth); printf("AuthenticatedSafe Length %u {\n", (unsigned)dci.content.data->Length); rtn = authSafeParse(*dci.content.data, pinfo, depth+3); doIndent(depth); printf("}\n"); } else { printf("Not parsing any other content type today.\n"); } if(pfx.macData) { doIndent(depth); printf("Mac Data {\n"); p12MacParse(*pfx.macData, pinfo, depth+3); doIndent(depth); printf("}\n"); if(pinfo.mPwd.Data == NULL) { doIndent(depth); printf("=== MAC not verified (no passphrase)===\n"); } else { CSSM_RETURN crtn = p12VerifyMac_app(pfx, pinfo.mCspHand, pinfo.mPwd, pinfo.mCoder); doIndent(depth); if(crtn) { cssmPerror("p12VerifyMac", crtn); doIndent(depth); printf("***MAC verify failure.\n"); } else { printf("MAC verifies OK.\n"); } } } return 0; }
static int encryptedDataDecrypt( const NSS_P7_EncryptedData &edata, P12ParseInfo &pinfo, NSS_P12_PBE_Params *pbep, // preparsed CSSM_DATA &ptext) // result goes here in pinfo.coder space { /* see if we can grok the encr alg */ CSSM_ALGORITHMS keyAlg; // e.g., CSSM_ALGID_DES CSSM_ALGORITHMS encrAlg; // e.g., CSSM_ALGID_3DES_3KEY_EDE CSSM_ALGORITHMS pbeHashAlg; // SHA1 or MD5 uint32 keySizeInBits; uint32 blockSizeInBytes; // for IV, optional CSSM_PADDING padding; // CSSM_PADDING_PKCS7, etc. CSSM_ENCRYPT_MODE mode; // CSSM_ALGMODE_CBCPadIV8, etc. #if IMPORT_EXPORT_COMPLETE PKCS_Which pkcs; bool found = pkcsOidToParams(&edata.contentInfo.encrAlg.algorithm, keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, padding, mode, pkcs); #else bool found = pkcsOidToParams(&edata.contentInfo.encrAlg.algorithm, keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, padding, mode); #endif /* IMPORT_EXPORT_COMPLETE */ if(!found) { printf("***EncryptedData encrAlg not understood\n"); return 1; } unsigned iterCount = dataToInt(pbep->iterations); /* go */ CSSM_RETURN crtn = p12Decrypt_app(pinfo.mCspHand, edata.contentInfo.encrContent, keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, padding, mode, iterCount, pbep->salt, pinfo.mPwd, pinfo.mCoder, ptext); #if WRITE_DECRYPT_TEXT if(crtn == 0) { char fname[100]; sprintf(fname, "decrypt%d.der", ctr++); writeFile(fname, ptext.Data, ptext.Length); printf("...wrote %u bytes to %s\n", (unsigned)ptext.Length, fname); } #endif return crtn ? 1 : 0; }
static int writeAuthSafeContent( const CSSM_DATA &rawBlob, const char *outFile, SecNssCoder &coder, OidParser &parser) { NSS_P12_RawPFX pfx; memset(&pfx, 0, sizeof(pfx)); if(coder.decodeItem(rawBlob, NSS_P12_RawPFXTemplate, &pfx)) { printf("***Error on top-level decode of NSS_P12_RawPFX\n"); return 1; } printf("...version = %u\n", (unsigned)dataToInt(pfx.version)); NSS_P7_RawContentInfo &rci = pfx.authSafe; printf("...contentType = %s\n", oidStr(rci.contentType, parser)); /* parse content per OID the only special case is PKCS7_Data, * which we unwrap from an octet string before writing it */ CSSM_DATA toWrite; if(nssCompareCssmData(&rci.contentType, &CSSMOID_PKCS7_Data)) { if(coder.decodeItem(rci.content, SEC_OctetStringTemplate, &toWrite)) { printf("***Error decoding PKCS7_Data Octet string; writing" " raw contents\n"); toWrite = rci.content; } } else if(nssCompareCssmData(&rci.contentType, &CSSMOID_PKCS7_SignedData)) { /* the only other legal content type here */ /* This is encoded SignedData which I am not even close * to worrying about - Panther p12 won't do this */ toWrite = rci.content; } else { printf("***writeAuthSafeContent: bad contentType\n"); return 1; } if(writeFile(outFile, toWrite.Data, toWrite.Length)) { printf("***Error writing to %s\n", outFile); return 1; } else { printf("...%u bytes written to %s\n", (unsigned)toWrite.Length, outFile); return 0; } }
/* * Parse an CSSM_X509_ALGORITHM_IDENTIFIER specific to P12. * Decode the alg params as a NSS_P12_PBE_Params and parse and * return the result if the pbeParams is non-NULL. */ static int p12AlgIdParse( const CSSM_X509_ALGORITHM_IDENTIFIER &algId, NSS_P12_PBE_Params *pbeParams, // optional P12ParseInfo &pinfo, unsigned depth) // print indent depth { doIndent(depth); printf("encrAlg = %s\n", oidStr(algId.algorithm, pinfo.mParser)); const CSSM_DATA ¶m = algId.parameters; if(pbeParams == NULL) { /* alg params are uninterpreted */ doIndent(depth); printf("Alg Params : "); printDataAsHex(¶m); return 0; } if(param.Length == 0) { printf("===warning: no alg parameters, this is not optional\n"); return 0; } memset(pbeParams, 0, sizeof(*pbeParams)); if(pinfo.mCoder.decodeItem(param, NSS_P12_PBE_ParamsTemplate, pbeParams)) { printf("***Error decoding NSS_P12_PBE_Params\n"); return 1; } doIndent(depth); printf("Salt : "); printDataAsHex(&pbeParams->salt); doIndent(depth); if(pbeParams->iterations.Length > 4) { printf("warning: iterations greater than max int\n"); doIndent(depth); printf("Iterations : "); printDataAsHex(&pbeParams->iterations); } else { printf("Iterations : %u\n", (unsigned)dataToInt(pbeParams->iterations)); } return 0; }
void PromelaDataModel::setVariable(void* ast, Data value) { PromelaParserNode* node = (PromelaParserNode*)ast; std::list<PromelaParserNode*>::iterator opIter = node->operands.begin(); switch (node->type) { case PML_VAR_ARRAY: { PromelaParserNode* name = *opIter++; PromelaParserNode* expr = *opIter++; if (INVALID_ASSIGNMENT(name->value)) { ERROR_EXECUTION_THROW("Cannot assign to " + name->value); } int index = dataToInt(evaluateExpr(expr)); if (_variables.compound.find(name->value) == _variables.compound.end()) { ERROR_EXECUTION_THROW("No variable " + name->value + " was declared"); } if (!_variables[name->value].hasKey("size")) { ERROR_EXECUTION_THROW("Variable " + name->value + " is no array"); } if (strTo<int>(_variables[name->value]["size"].atom) <= index) { ERROR_EXECUTION_THROW("Index " + toStr(index) + " in array " + name->value + "[" + _variables[name->value]["size"].atom + "] is out of bounds"); } _variables.compound[name->value].compound["value"][index] = value; break; } case PML_NAME: if (INVALID_ASSIGNMENT(node->value)) { ERROR_EXECUTION_THROW("Cannot assign to " + node->value); } _variables.compound[node->value].compound["value"] = value; break; default: break; } // std::cout << Data::toJSON(_variables) << std::endl; }
bool PromelaDataModel::dataToBool(const Data& data) { if (data.atom.size() == 0) // empty string or undefined return false; if (data.type == Data::VERBATIM) { // non-empty string is true return true; } else { if (data.atom.compare("true") == 0) { // boolean true is true return true; } else if (data.atom.compare("false") == 0) { return false; } else if (dataToInt(data) != 0) { return true; // non zero values are true } } return false; }
int16_t Utils::blockForIntData(int16_t rID, int16_t aID, IncomingPacketReader *incomingPacketReader) { IncomingPacket p = blockForPacket(rID, aID, incomingPacketReader); return p.isEmpty() ? -1 : dataToInt(p.data); }
/* * ShroudedKeyBag parser w/decrypt */ static int shroudedKeyBagParse( const NSS_P12_ShroudedKeyBag *keyBag, P12ParseInfo &pinfo, unsigned depth) { const CSSM_X509_ALGORITHM_IDENTIFIER &algId = keyBag->algorithm; NSS_P12_PBE_Params pbep; if(p12AlgIdParse(algId, &pbep, pinfo, depth)) { return 1; } if(pinfo.mPwd.Data == NULL) { doIndent(depth); printf("=== Key not decrypted (no passphrase)===\n"); return 0; } /* * Prepare for decryption */ CSSM_ALGORITHMS keyAlg; // e.g., CSSM_ALGID_DES CSSM_ALGORITHMS encrAlg; // e.g., CSSM_ALGID_3DES_3KEY_EDE CSSM_ALGORITHMS pbeHashAlg; // SHA1 or MD5 uint32 keySizeInBits; uint32 blockSizeInBytes; // for IV, optional CSSM_PADDING padding; // CSSM_PADDING_PKCS7, etc. CSSM_ENCRYPT_MODE mode; // CSSM_ALGMODE_CBCPadIV8, etc. #if IMPORT_EXPORT_COMPLETE PKCS_Which pkcs; bool found = pkcsOidToParams(&algId.algorithm, keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, padding, mode, pkcs); #else bool found = pkcsOidToParams(&algId.algorithm, keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, padding, mode); #endif if(!found) { printf("***ShroudedKeyBag encrAlg not understood\n"); return 1; } unsigned iterCount = dataToInt(pbep.iterations); CSSM_DATA berPrivKey; /* decrypt, result is BER encoded private key */ CSSM_RETURN crtn = p12Decrypt_app(pinfo.mCspHand, keyBag->encryptedData, keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, padding, mode, iterCount, pbep.salt, pinfo.mPwd, pinfo.mCoder, berPrivKey); if(crtn) { doIndent(depth); printf("***Error decrypting private key\n"); return 1; } /* decode */ NSS_PrivateKeyInfo privKey; memset(&privKey, 0, sizeof(privKey)); if(pinfo.mCoder.decodeItem(berPrivKey, kSecAsn1PrivateKeyInfoTemplate, &privKey)) { doIndent(depth); printf("***Error decoding decrypted private key\n"); return 1; } /* * in P12 library, we'd convert the result into a CSSM_KEY * or a SecItem... */ CSSM_X509_ALGORITHM_IDENTIFIER &privAlg = privKey.algorithm; doIndent(depth); printf("Priv Key Alg : %s\n", oidStr(privAlg.algorithm, pinfo.mParser)); doIndent(depth); printf("Priv Key Blob : "); printDataAsHex(&privKey.privateKey, 16); unsigned numAttrs = nssArraySize((const void**)privKey.attributes); if(numAttrs) { doIndent(depth+3); printf("numAttrs = %u\n", numAttrs); for(unsigned i=0; i<numAttrs; i++) { doIndent(depth+3); printf("attr[%u]:\n", i); attrParse(privKey.attributes[i], pinfo, depth+6); } } return 0; }
Data PromelaDataModel::getVariable(void* ast) { PromelaParserNode* node = (PromelaParserNode*)ast; // node->dump(); std::list<PromelaParserNode*>::iterator opIter = node->operands.begin(); switch(node->type) { case PML_NAME: if (_variables.compound.find(node->value) == _variables.compound.end()) { ERROR_EXECUTION_THROW("No variable " + node->value + " was declared"); } // if (_variables[node->value].compound.find("size") != _variables[node->value].compound.end()) { // ERROR_EXECUTION_THROW("Type error: Variable " + node->value + " is an array"); // } return _variables[node->value]["value"]; case PML_VAR_ARRAY: { PromelaParserNode* name = *opIter++; PromelaParserNode* expr = *opIter++; int index = dataToInt(evaluateExpr(expr)); if (_variables.compound.find(name->value) == _variables.compound.end()) { ERROR_EXECUTION_THROW("No variable " + name->value + " was declared"); } if (!_variables[name->value].hasKey("size")) { ERROR_EXECUTION_THROW("Variable " + name->value + " is no array"); } if (strTo<int>(_variables[name->value]["size"].atom) <= index) { ERROR_EXECUTION_THROW("Index " + toStr(index) + " in array " + name->value + "[" + _variables[name->value]["size"].atom + "] is out of bounds"); } return _variables.compound[name->value].compound["value"][index]; } case PML_CMPND: { // node->dump(); // std::cout << Data::toJSON(_variables["_event"]); std::stringstream idPath; PromelaParserNode* name = *opIter++; // special case for _x variables if (name->value.compare("_x") == 0) { PromelaParserNode* what = *opIter++; if (what->type == PML_VAR_ARRAY) { if (what->operands.size() == 2) { std::string arrName = what->operands.front()->value; std::string index = what->operands.back()->value; if (what->operands.back()->type == PML_STRING) { index = index.substr(1, index.size() - 2); // remove quotes } if (arrName.compare("states") == 0) { return Data(_interpreter->isInState(index)); } } } ERROR_EXECUTION_THROW("No variable " + name->value + " was declared"); } if (_variables.compound.find(name->value) == _variables.compound.end()) { ERROR_EXECUTION_THROW("No variable " + name->value + " was declared"); } Data currData = _variables.compound[name->value]["value"]; idPath << name->value; while(opIter != node->operands.end()) { std::string key = (*opIter)->value; idPath << "." << key; if (currData.compound.find(key) == currData.compound.end()) { ERROR_EXECUTION_THROW("No variable " + idPath.str() + " was declared"); } Data tmp = currData.compound[key]; currData = tmp; opIter++; } return currData; } default: ERROR_EXECUTION_THROW("Retrieving value of " + PromelaParserNode::typeToDesc(node->type) + " variable not implemented"); } return 0; }
Data PromelaDataModel::evaluateExpr(void* ast) { PromelaParserNode* node = (PromelaParserNode*)ast; std::list<PromelaParserNode*>::iterator opIter = node->operands.begin(); switch (node->type) { case PML_CONST: if (iequals(node->value, "false")) return Data(false); if (iequals(node->value, "true")) return Data(true); return strTo<int>(node->value); case PML_NAME: case PML_VAR_ARRAY: case PML_CMPND: return getVariable(node); case PML_STRING: { std::string stripped = node->value.substr(1, node->value.size() - 2); return Data(stripped, Data::VERBATIM); } case PML_PLUS: return dataToInt(evaluateExpr(*opIter++)) + dataToInt(evaluateExpr(*opIter++)); case PML_MINUS: return dataToInt(evaluateExpr(*opIter++)) - dataToInt(evaluateExpr(*opIter++)); case PML_DIVIDE: return dataToInt(evaluateExpr(*opIter++)) / dataToInt(evaluateExpr(*opIter++)); case PML_MODULO: return dataToInt(evaluateExpr(*opIter++)) % dataToInt(evaluateExpr(*opIter++)); case PML_EQ: { PromelaParserNode* lhs = *opIter++; PromelaParserNode* rhs = *opIter++; Data left = evaluateExpr(lhs); Data right = evaluateExpr(rhs); if (left == right) // overloaded operator== return Data(true); // literal strings or strings in variables if ((lhs->type == PML_STRING || rhs->type == PML_STRING) || (left.type == Data::VERBATIM && right.type == Data::VERBATIM)) { return (left.atom.compare(right.atom) == 0 ? Data(true) : Data(false)); } return dataToInt(left) == dataToInt(right); } case PML_NEG: return !dataToBool(evaluateExpr(*opIter++)); case PML_LT: return dataToInt(evaluateExpr(*opIter++)) < dataToInt(evaluateExpr(*opIter++)); case PML_LE: return dataToInt(evaluateExpr(*opIter++)) <= dataToInt(evaluateExpr(*opIter++)); case PML_GT: return dataToInt(evaluateExpr(*opIter++)) > dataToInt(evaluateExpr(*opIter++)); case PML_GE: return dataToInt(evaluateExpr(*opIter++)) >= dataToInt(evaluateExpr(*opIter++)); case PML_TIMES: return dataToInt(evaluateExpr(*opIter++)) * dataToInt(evaluateExpr(*opIter++)); case PML_LSHIFT: return dataToInt(evaluateExpr(*opIter++)) << dataToInt(evaluateExpr(*opIter++)); case PML_RSHIFT: return dataToInt(evaluateExpr(*opIter++)) >> dataToInt(evaluateExpr(*opIter++)); case PML_AND: case PML_OR: { PromelaParserNode* lhs = *opIter++; PromelaParserNode* rhs = *opIter++; std::cout << "-----" << std::endl; lhs->dump(); rhs->dump(); Data left = evaluateExpr(lhs); Data right = evaluateExpr(rhs); bool truthLeft = dataToBool(left); bool truthRight = dataToBool(right); if (node->type == PML_AND) { return truthLeft && truthRight; } else { return truthLeft || truthRight; } } default: ERROR_EXECUTION_THROW("Support for " + PromelaParserNode::typeToDesc(node->type) + " expressions not implemented"); } return 0; }
void PromelaDataModel::evaluateDecl(void* ast) { PromelaParserNode* node = (PromelaParserNode*)ast; if (false) { } else if (node->type == PML_DECL) { std::list<PromelaParserNode*>::iterator opIter = node->operands.begin(); PromelaParserNode* vis = *opIter++; PromelaParserNode* type = *opIter++; PromelaParserNode* varlist = *opIter++; for (std::list<PromelaParserNode*>::iterator nameIter = varlist->operands.begin(); nameIter != varlist->operands.end(); nameIter++) { Data variable; variable.compound["vis"] = Data(vis->value, Data::VERBATIM); variable.compound["type"] = Data(type->value, Data::VERBATIM); if (false) { } else if ((*nameIter)->type == PML_NAME) { // plain variables without initial assignment if (type->value == "mtype") { variable.compound["value"] = Data(_lastMType++, Data::INTERPRETED); } else { variable.compound["value"] = Data(0, Data::INTERPRETED); } _variables.compound[(*nameIter)->value] = variable; } else if ((*nameIter)->type == PML_ASGN) { // initially assigned variables std::list<PromelaParserNode*>::iterator opIterAsgn = (*nameIter)->operands.begin(); PromelaParserNode* name = *opIterAsgn++; PromelaParserNode* expr = *opIterAsgn++; variable.compound["value"] = evaluateExpr(expr); assert(opIterAsgn == (*nameIter)->operands.end()); _variables.compound[name->value] = variable; } else if ((*nameIter)->type == PML_VAR_ARRAY) { // variable arrays std::list<PromelaParserNode*>::iterator opIterAsgn = (*nameIter)->operands.begin(); PromelaParserNode* name = *opIterAsgn++; int size = dataToInt(evaluateExpr(*opIterAsgn++)); variable.compound["size"] = size; for (int i = 0; i < size; i++) { variable.compound["value"].array.push_back(Data(0, Data::INTERPRETED)); } assert(opIterAsgn == (*nameIter)->operands.end()); _variables.compound[name->value] = variable; } else { ERROR_EXECUTION_THROW("Declaring variables via " + PromelaParserNode::typeToDesc((*nameIter)->type) + " not implemented"); } } assert(opIter == node->operands.end()); } else if (node->type == PML_DECLLIST) { for (std::list<PromelaParserNode*>::iterator declIter = node->operands.begin(); declIter != node->operands.end(); declIter++) { evaluateDecl(*declIter); } } else { ERROR_EXECUTION_THROW("Declaring variables via " + PromelaParserNode::typeToDesc(node->type) + " not implemented"); } }