/** * XML Security Library (http://www.aleksey.com/xmlsec). * * "XML Encryption" implementation * http://www.w3.org/TR/xmlenc-core * * This is free software; see Copyright file in the source * distribution for preciese wording. * * Copyright (C) 2002-2003 Aleksey Sanin */ #include "globals.h" #ifndef XMLSEC_NO_XMLENC #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int xmlSecEncCtxEncDataNodeRead (xmlSecEncCtxPtr encCtx, xmlNodePtr node); static int xmlSecEncCtxEncDataNodeWrite (xmlSecEncCtxPtr encCtx); static int xmlSecEncCtxCipherDataNodeRead (xmlSecEncCtxPtr encCtx, xmlNodePtr node); static int xmlSecEncCtxCipherReferenceNodeRead (xmlSecEncCtxPtr encCtx, xmlNodePtr node); /* The ID attribute in XMLEnc is 'Id' */ static const xmlChar* xmlSecEncIds[] = { BAD_CAST "Id", NULL }; /** * xmlSecEncCtxCreate: * @keysMngr: the pointer to keys manager. * * Creates element processing context. * The caller is responsible for destroying returned object by calling * #xmlSecEncCtxDestroy function. * * Returns: pointer to newly allocated context object or NULL if an error * occurs. */ xmlSecEncCtxPtr xmlSecEncCtxCreate(xmlSecKeysMngrPtr keysMngr) { xmlSecEncCtxPtr encCtx; int ret; encCtx = (xmlSecEncCtxPtr) xmlMalloc(sizeof(xmlSecEncCtx)); if(encCtx == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, NULL, XMLSEC_ERRORS_R_MALLOC_FAILED, "sizeof(xmlSecEncCtx)=%d", sizeof(xmlSecEncCtx)); return(NULL); } ret = xmlSecEncCtxInitialize(encCtx, keysMngr); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecEncCtxInitialize", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); xmlSecEncCtxDestroy(encCtx); return(NULL); } return(encCtx); } /** * xmlSecEncCtxDestroy: * @encCtx: the pointer to processing context. * * Destroy context object created with #xmlSecEncCtxCreate function. */ void xmlSecEncCtxDestroy(xmlSecEncCtxPtr encCtx) { xmlSecAssert(encCtx != NULL); xmlSecEncCtxFinalize(encCtx); xmlFree(encCtx); } /** * xmlSecEncCtxInitialize: * @encCtx: the pointer to processing context. * @keysMngr: the pointer to keys manager. * * Initializes element processing context. * The caller is responsible for cleaning up returned object by calling * #xmlSecEncCtxFinalize function. * * Returns: 0 on success or a negative value if an error occurs. */ int xmlSecEncCtxInitialize(xmlSecEncCtxPtr encCtx, xmlSecKeysMngrPtr keysMngr) { int ret; xmlSecAssert2(encCtx != NULL, -1); memset(encCtx, 0, sizeof(xmlSecEncCtx)); /* initialize key info */ ret = xmlSecKeyInfoCtxInitialize(&(encCtx->keyInfoReadCtx), keysMngr); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecKeyInfoCtxInitialize", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } encCtx->keyInfoReadCtx.mode = xmlSecKeyInfoModeRead; ret = xmlSecKeyInfoCtxInitialize(&(encCtx->keyInfoWriteCtx), keysMngr); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecKeyInfoCtxInitialize", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } encCtx->keyInfoWriteCtx.mode = xmlSecKeyInfoModeWrite; /* it's not wise to write private key :) */ encCtx->keyInfoWriteCtx.keyReq.keyType = xmlSecKeyDataTypePublic; /* initializes transforms encCtx */ ret = xmlSecTransformCtxInitialize(&(encCtx->transformCtx)); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxInitialize", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } return(0); } /** * xmlSecEncCtxFinalize: * @encCtx: the pointer to processing context. * * Cleans up @encCtx object. */ void xmlSecEncCtxFinalize(xmlSecEncCtxPtr encCtx) { xmlSecAssert(encCtx != NULL); xmlSecEncCtxReset(encCtx); xmlSecTransformCtxFinalize(&(encCtx->transformCtx)); xmlSecKeyInfoCtxFinalize(&(encCtx->keyInfoReadCtx)); xmlSecKeyInfoCtxFinalize(&(encCtx->keyInfoWriteCtx)); memset(encCtx, 0, sizeof(xmlSecEncCtx)); } /** * xmlSecEncCtxReset: * @encCtx: the pointer to processing context. * * Resets @encCtx object, user settings are not touched. */ void xmlSecEncCtxReset(xmlSecEncCtxPtr encCtx) { xmlSecAssert(encCtx != NULL); xmlSecTransformCtxReset(&(encCtx->transformCtx)); xmlSecKeyInfoCtxReset(&(encCtx->keyInfoReadCtx)); xmlSecKeyInfoCtxReset(&(encCtx->keyInfoWriteCtx)); encCtx->operation = xmlSecTransformOperationNone; encCtx->result = NULL; encCtx->resultBase64Encoded = 0; encCtx->resultReplaced = 0; encCtx->encMethod = NULL; if (encCtx->replacedNodeList != NULL) { xmlFreeNodeList(encCtx->replacedNodeList); encCtx->replacedNodeList = NULL; } if(encCtx->encKey != NULL) { xmlSecKeyDestroy(encCtx->encKey); encCtx->encKey = NULL; } if(encCtx->id != NULL) { xmlFree(encCtx->id); encCtx->id = NULL; } if(encCtx->type != NULL) { xmlFree(encCtx->type); encCtx->type = NULL; } if(encCtx->mimeType != NULL) { xmlFree(encCtx->mimeType); encCtx->mimeType = NULL; } if(encCtx->encoding != NULL) { xmlFree(encCtx->encoding); encCtx->encoding = NULL; } if(encCtx->recipient != NULL) { xmlFree(encCtx->recipient); encCtx->recipient = NULL; } if(encCtx->carriedKeyName != NULL) { xmlFree(encCtx->carriedKeyName); encCtx->carriedKeyName = NULL; } encCtx->encDataNode = encCtx->encMethodNode = encCtx->keyInfoNode = encCtx->cipherValueNode = NULL; } /** * xmlSecEncCtxCopyUserPref: * @dst: the pointer to destination context. * @src: the pointer to source context. * * Copies user preference from @src context to @dst. * * Returns: 0 on success or a negative value if an error occurs. */ int xmlSecEncCtxCopyUserPref(xmlSecEncCtxPtr dst, xmlSecEncCtxPtr src) { int ret; xmlSecAssert2(dst != NULL, -1); xmlSecAssert2(src != NULL, -1); dst->userData = src->userData; dst->flags = src->flags; dst->flags2 = src->flags2; dst->defEncMethodId = src->defEncMethodId; dst->mode = src->mode; ret = xmlSecTransformCtxCopyUserPref(&(dst->transformCtx), &(src->transformCtx)); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxCopyUserPref", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } ret = xmlSecKeyInfoCtxCopyUserPref(&(dst->keyInfoReadCtx), &(src->keyInfoReadCtx)); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecKeyInfoCtxCopyUserPref", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } ret = xmlSecKeyInfoCtxCopyUserPref(&(dst->keyInfoWriteCtx), &(src->keyInfoWriteCtx)); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecKeyInfoCtxCopyUserPref", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } return(0); } /** * xmlSecEncCtxBinaryEncrypt: * @encCtx: the pointer to processing context. * @tmpl: the pointer to template node. * @data: the pointer for binary buffer. * @dataSize: the @data buffer size. * * Encrypts @data according to template @tmpl. * * Returns: 0 on success or a negative value if an error occurs. */ int xmlSecEncCtxBinaryEncrypt(xmlSecEncCtxPtr encCtx, xmlNodePtr tmpl, const xmlSecByte* data, xmlSecSize dataSize) { int ret; xmlSecAssert2(encCtx != NULL, -1); xmlSecAssert2(encCtx->result == NULL, -1); xmlSecAssert2(tmpl != NULL, -1); xmlSecAssert2(data != NULL, -1); /* initialize context and add ID atributes to the list of known ids */ encCtx->operation = xmlSecTransformOperationEncrypt; xmlSecAddIDs(tmpl->doc, tmpl, xmlSecEncIds); /* read the template and set encryption method, key, etc. */ ret = xmlSecEncCtxEncDataNodeRead(encCtx, tmpl); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecEncCtxEncDataNodeRead", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } ret = xmlSecTransformCtxBinaryExecute(&(encCtx->transformCtx), data, dataSize); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxBinaryExecute", XMLSEC_ERRORS_R_XMLSEC_FAILED, "dataSize=%d", dataSize); return(-1); } encCtx->result = encCtx->transformCtx.result; xmlSecAssert2(encCtx->result != NULL, -1); ret = xmlSecEncCtxEncDataNodeWrite(encCtx); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecEncCtxEncDataNodeWrite", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } return(0); } /** * xmlSecEncCtxXmlEncrypt: * @encCtx: the pointer to processing context. * @tmpl: the pointer to template node. * @node: the pointer to node for encryption. * * Encrypts @node according to template @tmpl. If requested, @node is replaced * with result node. * * Returns: 0 on success or a negative value if an error occurs. */ int xmlSecEncCtxXmlEncrypt(xmlSecEncCtxPtr encCtx, xmlNodePtr tmpl, xmlNodePtr node) { xmlOutputBufferPtr output; int ret; xmlSecAssert2(encCtx != NULL, -1); xmlSecAssert2(encCtx->result == NULL, -1); xmlSecAssert2(tmpl != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(node->doc != NULL, -1); /* initialize context and add ID atributes to the list of known ids */ encCtx->operation = xmlSecTransformOperationEncrypt; xmlSecAddIDs(tmpl->doc, tmpl, xmlSecEncIds); /* read the template and set encryption method, key, etc. */ ret = xmlSecEncCtxEncDataNodeRead(encCtx, tmpl); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecEncCtxEncDataNodeRead", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } ret = xmlSecTransformCtxPrepare(&(encCtx->transformCtx), xmlSecTransformDataTypeBin); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxPrepare", XMLSEC_ERRORS_R_XMLSEC_FAILED, "type=bin"); return(-1); } xmlSecAssert2(encCtx->transformCtx.first != NULL, -1); output = xmlSecTransformCreateOutputBuffer(encCtx->transformCtx.first, &(encCtx->transformCtx)); if(output == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecTransformGetName(encCtx->transformCtx.first)), "xmlSecTransformCreateOutputBuffer", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } /* push data thru */ if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncElement)) { /* get the content of the node */ xmlNodeDumpOutput(output, node->doc, node, 0, 0, NULL); } else if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncContent)) { xmlNodePtr cur; /* get the content of the nodes childs */ for(cur = node->children; cur != NULL; cur = cur->next) { xmlNodeDumpOutput(output, node->doc, cur, 0, 0, NULL); } } else { xmlSecError(XMLSEC_ERRORS_HERE, NULL, NULL, XMLSEC_ERRORS_R_INVALID_TYPE, "type=%s", xmlSecErrorsSafeString(encCtx->type)); xmlOutputBufferClose(output); return(-1); } /* close the buffer and flush everything */ ret = xmlOutputBufferClose(output); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlOutputBufferClose", XMLSEC_ERRORS_R_XML_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } encCtx->result = encCtx->transformCtx.result; xmlSecAssert2(encCtx->result != NULL, -1); ret = xmlSecEncCtxEncDataNodeWrite(encCtx); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecEncCtxEncDataNodeWrite", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } /* now we need to update our original document */ if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncElement)) { /* check if we need to return the replaced node */ if((encCtx->flags & XMLSEC_ENC_RETURN_REPLACED_NODE) != 0) { ret = xmlSecReplaceNodeAndReturn(node, tmpl, &(encCtx->replacedNodeList)); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecReplaceNode", XMLSEC_ERRORS_R_XMLSEC_FAILED, "node=%s", xmlSecErrorsSafeString(xmlSecNodeGetName(node))); return(-1); } } else { ret = xmlSecReplaceNode(node, tmpl); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecReplaceNode", XMLSEC_ERRORS_R_XMLSEC_FAILED, "node=%s", xmlSecErrorsSafeString(xmlSecNodeGetName(node))); return(-1); } } encCtx->resultReplaced = 1; } else if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncContent)) { /* check if we need to return the replaced node */ if((encCtx->flags & XMLSEC_ENC_RETURN_REPLACED_NODE) != 0) { ret = xmlSecReplaceContentAndReturn(node, tmpl, &(encCtx->replacedNodeList)); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecReplaceContentAndReturn", XMLSEC_ERRORS_R_XMLSEC_FAILED, "node=%s", xmlSecErrorsSafeString(xmlSecNodeGetName(node))); return(-1); } } else { ret = xmlSecReplaceContent(node, tmpl); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecReplaceContent", XMLSEC_ERRORS_R_XMLSEC_FAILED, "node=%s", xmlSecErrorsSafeString(xmlSecNodeGetName(node))); return(-1); } } encCtx->resultReplaced = 1; } else { /* we should've catached this error before */ xmlSecError(XMLSEC_ERRORS_HERE, NULL, NULL, XMLSEC_ERRORS_R_INVALID_TYPE, "type=%s", xmlSecErrorsSafeString(encCtx->type)); return(-1); } return(0); } /** * xmlSecEncCtxUriEncrypt: * @encCtx: the pointer to processing context. * @tmpl: the pointer to template node. * @uri: the URI. * * Encrypts data from @uri according to template @tmpl. * * Returns: 0 on success or a negative value if an error occurs. */ int xmlSecEncCtxUriEncrypt(xmlSecEncCtxPtr encCtx, xmlNodePtr tmpl, const xmlChar *uri) { int ret; xmlSecAssert2(encCtx != NULL, -1); xmlSecAssert2(encCtx->result == NULL, -1); xmlSecAssert2(tmpl != NULL, -1); xmlSecAssert2(uri != NULL, -1); /* initialize context and add ID atributes to the list of known ids */ encCtx->operation = xmlSecTransformOperationEncrypt; xmlSecAddIDs(tmpl->doc, tmpl, xmlSecEncIds); /* we need to add input uri transform first */ ret = xmlSecTransformCtxSetUri(&(encCtx->transformCtx), uri, tmpl); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxSetUri", XMLSEC_ERRORS_R_XMLSEC_FAILED, "uri=%s", xmlSecErrorsSafeString(uri)); return(-1); } /* read the template and set encryption method, key, etc. */ ret = xmlSecEncCtxEncDataNodeRead(encCtx, tmpl); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecEncCtxEncDataNodeRead", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } /* encrypt the data */ ret = xmlSecTransformCtxExecute(&(encCtx->transformCtx), tmpl->doc); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxExecute", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } encCtx->result = encCtx->transformCtx.result; xmlSecAssert2(encCtx->result != NULL, -1); ret = xmlSecEncCtxEncDataNodeWrite(encCtx); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecEncCtxEncDataNodeWrite", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } return(0); } /** * xmlSecEncCtxDecrypt: * @encCtx: the pointer to processing context. * @node: the pointer to node. * * Decrypts @node and if necessary replaces @node with decrypted data. * * Returns: 0 on success or a negative value if an error occurs. */ int xmlSecEncCtxDecrypt(xmlSecEncCtxPtr encCtx, xmlNodePtr node) { xmlSecBufferPtr buffer; int ret; xmlSecAssert2(encCtx != NULL, -1); xmlSecAssert2(node != NULL, -1); /* decrypt */ buffer = xmlSecEncCtxDecryptToBuffer(encCtx, node); if(buffer == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecEncCtxDecryptToBuffer", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } /* replace original node if requested */ if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncElement)) { /* check if we need to return the replaced node */ if((encCtx->flags & XMLSEC_ENC_RETURN_REPLACED_NODE) != 0) { ret = xmlSecReplaceNodeBufferAndReturn(node, xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer), &(encCtx->replacedNodeList)); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecReplaceNodeBufferAndReturn", XMLSEC_ERRORS_R_XMLSEC_FAILED, "node=%s", xmlSecErrorsSafeString(xmlSecNodeGetName(node))); return(-1); } } else { ret = xmlSecReplaceNodeBuffer(node, xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer)); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecReplaceNodeBuffer", XMLSEC_ERRORS_R_XMLSEC_FAILED, "node=%s", xmlSecErrorsSafeString(xmlSecNodeGetName(node))); return(-1); } } encCtx->resultReplaced = 1; } else if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncContent)) { /* replace the node with the buffer */ /* check if we need to return the replaced node */ if((encCtx->flags & XMLSEC_ENC_RETURN_REPLACED_NODE) != 0) { ret = xmlSecReplaceNodeBufferAndReturn(node, xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer), &(encCtx->replacedNodeList)); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecReplaceNodeBufferAndReturn", XMLSEC_ERRORS_R_XMLSEC_FAILED, "node=%s", xmlSecErrorsSafeString(xmlSecNodeGetName(node))); return(-1); } } else { ret = xmlSecReplaceNodeBuffer(node, xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer)); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecReplaceNodeBuffer", XMLSEC_ERRORS_R_XMLSEC_FAILED, "node=%s", xmlSecErrorsSafeString(xmlSecNodeGetName(node))); return(-1); } } encCtx->resultReplaced = 1; } return(0); } /** * xmlSecEncCtxDecryptToBuffer: * @encCtx: the pointer to processing context. * @node: the pointer to node. * * Decrypts @node data to the @encCtx buffer. * * Returns: 0 on success or a negative value if an error occurs. */ xmlSecBufferPtr xmlSecEncCtxDecryptToBuffer(xmlSecEncCtxPtr encCtx, xmlNodePtr node) { int ret; xmlSecAssert2(encCtx != NULL, NULL); xmlSecAssert2(encCtx->result == NULL, NULL); xmlSecAssert2(node != NULL, NULL); /* initialize context and add ID atributes to the list of known ids */ encCtx->operation = xmlSecTransformOperationDecrypt; xmlSecAddIDs(node->doc, node, xmlSecEncIds); ret = xmlSecEncCtxEncDataNodeRead(encCtx, node); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecEncCtxEncDataNodeRead", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(NULL); } /* decrypt the data */ if(encCtx->cipherValueNode != NULL) { xmlChar* data = NULL; xmlSecSize dataSize = 0; data = xmlNodeGetContent(encCtx->cipherValueNode); if(data == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, xmlSecErrorsSafeString(xmlSecNodeGetName(encCtx->cipherValueNode)), XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, XMLSEC_ERRORS_NO_MESSAGE); return(NULL); } dataSize = xmlStrlen(data); ret = xmlSecTransformCtxBinaryExecute(&(encCtx->transformCtx), data, dataSize); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxBinaryExecute", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); if(data != NULL) { xmlFree(data); } return(NULL); } if(data != NULL) { xmlFree(data); } } else { ret = xmlSecTransformCtxExecute(&(encCtx->transformCtx), node->doc); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxBinaryExecute", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(NULL); } } encCtx->result = encCtx->transformCtx.result; xmlSecAssert2(encCtx->result != NULL, NULL); return(encCtx->result); } static int xmlSecEncCtxEncDataNodeRead(xmlSecEncCtxPtr encCtx, xmlNodePtr node) { xmlNodePtr cur; int ret; xmlSecAssert2(encCtx != NULL, -1); xmlSecAssert2((encCtx->operation == xmlSecTransformOperationEncrypt) || (encCtx->operation == xmlSecTransformOperationDecrypt), -1); xmlSecAssert2(node != NULL, -1); switch(encCtx->mode) { case xmlEncCtxModeEncryptedData: if(!xmlSecCheckNodeName(node, xmlSecNodeEncryptedData, xmlSecEncNs)) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, xmlSecErrorsSafeString(xmlSecNodeGetName(node)), XMLSEC_ERRORS_R_INVALID_NODE, "expected=%s", xmlSecErrorsSafeString(xmlSecNodeEncryptedData)); return(-1); } break; case xmlEncCtxModeEncryptedKey: if(!xmlSecCheckNodeName(node, xmlSecNodeEncryptedKey, xmlSecEncNs)) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, xmlSecErrorsSafeString(xmlSecNodeGetName(node)), XMLSEC_ERRORS_R_INVALID_NODE, "expected=%s", xmlSecErrorsSafeString(xmlSecNodeEncryptedKey)); return(-1); } break; } /* first read node data */ xmlSecAssert2(encCtx->id == NULL, -1); xmlSecAssert2(encCtx->type == NULL, -1); xmlSecAssert2(encCtx->mimeType == NULL, -1); xmlSecAssert2(encCtx->encoding == NULL, -1); xmlSecAssert2(encCtx->recipient == NULL, -1); xmlSecAssert2(encCtx->carriedKeyName == NULL, -1); encCtx->id = xmlGetProp(node, xmlSecAttrId); encCtx->type = xmlGetProp(node, xmlSecAttrType); encCtx->mimeType = xmlGetProp(node, xmlSecAttrMimeType); encCtx->encoding = xmlGetProp(node, xmlSecAttrEncoding); if(encCtx->mode == xmlEncCtxModeEncryptedKey) { encCtx->recipient = xmlGetProp(node, xmlSecAttrRecipient); /* todo: check recipient? */ } cur = xmlSecGetNextElementNode(node->children); /* first node is optional EncryptionMethod, we'll read it later */ xmlSecAssert2(encCtx->encMethodNode == NULL, -1); if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeEncryptionMethod, xmlSecEncNs))) { encCtx->encMethodNode = cur; cur = xmlSecGetNextElementNode(cur->next); } /* next node is optional KeyInfo, we'll process it later */ xmlSecAssert2(encCtx->keyInfoNode == NULL, -1); if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeKeyInfo, xmlSecDSigNs))) { encCtx->keyInfoNode = cur; cur = xmlSecGetNextElementNode(cur->next); } /* next is required CipherData node */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeCipherData, xmlSecEncNs))) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), XMLSEC_ERRORS_R_INVALID_NODE, "node=%s", xmlSecErrorsSafeString(xmlSecNodeCipherData)); return(-1); } ret = xmlSecEncCtxCipherDataNodeRead(encCtx, cur); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecEncCtxCipherDataNodeRead", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } cur = xmlSecGetNextElementNode(cur->next); /* next is optional EncryptionProperties node (we simply ignore it) */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeEncryptionProperties, xmlSecEncNs))) { cur = xmlSecGetNextElementNode(cur->next); } /* there are more possible nodes for the node */ if(encCtx->mode == xmlEncCtxModeEncryptedKey) { /* next is optional ReferenceList node (we simply ignore it) */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeReferenceList, xmlSecEncNs))) { cur = xmlSecGetNextElementNode(cur->next); } /* next is optional CarriedKeyName node (we simply ignore it) */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeCarriedKeyName, xmlSecEncNs))) { encCtx->carriedKeyName = xmlNodeGetContent(cur); if(encCtx->carriedKeyName == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, "node=%s", xmlSecErrorsSafeString(xmlSecNodeCipherData)); return(-1); } /* TODO: decode the name? */ cur = xmlSecGetNextElementNode(cur->next); } } /* if there is something left than it's an error */ if(cur != NULL) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), XMLSEC_ERRORS_R_UNEXPECTED_NODE, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } /* now read the encryption method node */ xmlSecAssert2(encCtx->encMethod == NULL, -1); if(encCtx->encMethodNode != NULL) { encCtx->encMethod = xmlSecTransformCtxNodeRead(&(encCtx->transformCtx), encCtx->encMethodNode, xmlSecTransformUsageEncryptionMethod); if(encCtx->encMethod == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxNodeRead", XMLSEC_ERRORS_R_XMLSEC_FAILED, "node=%s", xmlSecErrorsSafeString(xmlSecNodeGetName(encCtx->encMethodNode))); return(-1); } } else if(encCtx->defEncMethodId != xmlSecTransformIdUnknown) { encCtx->encMethod = xmlSecTransformCtxCreateAndAppend(&(encCtx->transformCtx), encCtx->defEncMethodId); if(encCtx->encMethod == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxAppend", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } } else { xmlSecError(XMLSEC_ERRORS_HERE, NULL, NULL, XMLSEC_ERRORS_R_INVALID_DATA, "encryption method not specified"); return(-1); } encCtx->encMethod->operation = encCtx->operation; /* we have encryption method, find key */ ret = xmlSecTransformSetKeyReq(encCtx->encMethod, &(encCtx->keyInfoReadCtx.keyReq)); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformSetKeyReq", XMLSEC_ERRORS_R_XMLSEC_FAILED, "transform=%s", xmlSecErrorsSafeString(xmlSecTransformGetName(encCtx->encMethod))); return(-1); } /* TODO: KeyInfo node != NULL and encKey != NULL */ if((encCtx->encKey == NULL) && (encCtx->keyInfoReadCtx.keysMngr != NULL) && (encCtx->keyInfoReadCtx.keysMngr->getKey != NULL)) { encCtx->encKey = (encCtx->keyInfoReadCtx.keysMngr->getKey)(encCtx->keyInfoNode, &(encCtx->keyInfoReadCtx)); } /* check that we have exactly what we want */ if((encCtx->encKey == NULL) || (!xmlSecKeyMatch(encCtx->encKey, NULL, &(encCtx->keyInfoReadCtx.keyReq)))) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, NULL, XMLSEC_ERRORS_R_KEY_NOT_FOUND, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } /* set the key to the transform */ ret = xmlSecTransformSetKey(encCtx->encMethod, encCtx->encKey); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformSetKey", XMLSEC_ERRORS_R_XMLSEC_FAILED, "transform=%s", xmlSecErrorsSafeString(xmlSecTransformGetName(encCtx->encMethod))); return(-1); } /* if we need to write result to xml node then we need base64 encode it */ if((encCtx->operation == xmlSecTransformOperationEncrypt) && (encCtx->cipherValueNode != NULL)) { xmlSecTransformPtr base64Encode; /* we need to add base64 encode transform */ base64Encode = xmlSecTransformCtxCreateAndAppend(&(encCtx->transformCtx), xmlSecTransformBase64Id); if(base64Encode == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxCreateAndAppend", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } base64Encode->operation = xmlSecTransformOperationEncode; encCtx->resultBase64Encoded = 1; } return(0); } static int xmlSecEncCtxEncDataNodeWrite(xmlSecEncCtxPtr encCtx) { int ret; xmlSecAssert2(encCtx != NULL, -1); xmlSecAssert2(encCtx->result != NULL, -1); xmlSecAssert2(encCtx->encKey != NULL, -1); /* write encrypted data to xml (if requested) */ if(encCtx->cipherValueNode != NULL) { xmlSecAssert2(xmlSecBufferGetData(encCtx->result) != NULL, -1); xmlNodeSetContentLen(encCtx->cipherValueNode, xmlSecBufferGetData(encCtx->result), xmlSecBufferGetSize(encCtx->result)); encCtx->resultReplaced = 1; } /* update node */ if(encCtx->keyInfoNode != NULL) { ret = xmlSecKeyInfoNodeWrite(encCtx->keyInfoNode, encCtx->encKey, &(encCtx->keyInfoWriteCtx)); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecKeyInfoNodeWrite", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } } return(0); } static int xmlSecEncCtxCipherDataNodeRead(xmlSecEncCtxPtr encCtx, xmlNodePtr node) { xmlNodePtr cur; int ret; xmlSecAssert2(encCtx != NULL, -1); xmlSecAssert2(node != NULL, -1); cur = xmlSecGetNextElementNode(node->children); /* we either have CipherValue or CipherReference node */ xmlSecAssert2(encCtx->cipherValueNode == NULL, -1); if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeCipherValue, xmlSecEncNs))) { /* don't need data from CipherData node when we are encrypting */ if(encCtx->operation == xmlSecTransformOperationDecrypt) { xmlSecTransformPtr base64Decode; /* we need to add base64 decode transform */ base64Decode = xmlSecTransformCtxCreateAndPrepend(&(encCtx->transformCtx), xmlSecTransformBase64Id); if(base64Decode == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxCreateAndPrepend", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } } encCtx->cipherValueNode = cur; cur = xmlSecGetNextElementNode(cur->next); } else if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeCipherReference, xmlSecEncNs))) { /* don't need data from CipherReference node when we are encrypting */ if(encCtx->operation == xmlSecTransformOperationDecrypt) { ret = xmlSecEncCtxCipherReferenceNodeRead(encCtx, cur); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecEncCtxCipherReferenceNodeRead", XMLSEC_ERRORS_R_XMLSEC_FAILED, "node=%s", xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); return(-1); } } cur = xmlSecGetNextElementNode(cur->next); } if(cur != NULL) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), XMLSEC_ERRORS_R_UNEXPECTED_NODE, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } return(0); } static int xmlSecEncCtxCipherReferenceNodeRead(xmlSecEncCtxPtr encCtx, xmlNodePtr node) { xmlNodePtr cur; xmlChar* uri; int ret; xmlSecAssert2(encCtx != NULL, -1); xmlSecAssert2(node != NULL, -1); /* first read the optional uri attr and check that we can process it */ uri = xmlGetProp(node, xmlSecAttrURI); ret = xmlSecTransformCtxSetUri(&(encCtx->transformCtx), uri, node); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxSetUri", XMLSEC_ERRORS_R_XMLSEC_FAILED, "uri=%s", xmlSecErrorsSafeString(uri)); xmlFree(uri); return(-1); } xmlFree(uri); cur = xmlSecGetNextElementNode(node->children); /* the only one node is optional Transforms node */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeTransforms, xmlSecEncNs))) { ret = xmlSecTransformCtxNodesListRead(&(encCtx->transformCtx), cur, xmlSecTransformUsageDSigTransform); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, "xmlSecTransformCtxNodesListRead", XMLSEC_ERRORS_R_XMLSEC_FAILED, "node=%s", xmlSecErrorsSafeString(xmlSecNodeGetName(encCtx->encMethodNode))); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* if there is something left than it's an error */ if(cur != NULL) { xmlSecError(XMLSEC_ERRORS_HERE, NULL, xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), XMLSEC_ERRORS_R_UNEXPECTED_NODE, XMLSEC_ERRORS_NO_MESSAGE); return(-1); } return(0); } /** * xmlSecEncCtxDebugDump: * @encCtx: the pointer to processing context. * @output: the pointer to output FILE. * * Prints the debug information about @encCtx to @output. */ void xmlSecEncCtxDebugDump(xmlSecEncCtxPtr encCtx, FILE* output) { xmlSecAssert(encCtx != NULL); xmlSecAssert(output != NULL); switch(encCtx->mode) { case xmlEncCtxModeEncryptedData: if(encCtx->operation == xmlSecTransformOperationEncrypt) { fprintf(output, "= DATA ENCRYPTION CONTEXT\n"); } else { fprintf(output, "= DATA DECRYPTION CONTEXT\n"); } break; case xmlEncCtxModeEncryptedKey: if(encCtx->operation == xmlSecTransformOperationEncrypt) { fprintf(output, "= KEY ENCRYPTION CONTEXT\n"); } else { fprintf(output, "= KEY DECRYPTION CONTEXT\n"); } break; } fprintf(output, "== Status: %s\n", (encCtx->resultReplaced) ? "replaced" : "not-replaced" ); fprintf(output, "== flags: 0x%08x\n", encCtx->flags); fprintf(output, "== flags2: 0x%08x\n", encCtx->flags2); if(encCtx->id != NULL) { fprintf(output, "== Id: \"%s\"\n", encCtx->id); } if(encCtx->type != NULL) { fprintf(output, "== Type: \"%s\"\n", encCtx->type); } if(encCtx->mimeType != NULL) { fprintf(output, "== MimeType: \"%s\"\n", encCtx->mimeType); } if(encCtx->encoding != NULL) { fprintf(output, "== Encoding: \"%s\"\n", encCtx->encoding); } if(encCtx->recipient != NULL) { fprintf(output, "== Recipient: \"%s\"\n", encCtx->recipient); } if(encCtx->carriedKeyName != NULL) { fprintf(output, "== CarriedKeyName: \"%s\"\n", encCtx->carriedKeyName); } fprintf(output, "== Key Info Read Ctx:\n"); xmlSecKeyInfoCtxDebugDump(&(encCtx->keyInfoReadCtx), output); fprintf(output, "== Key Info Write Ctx:\n"); xmlSecKeyInfoCtxDebugDump(&(encCtx->keyInfoWriteCtx), output); fprintf(output, "== Encryption Transform Ctx:\n"); xmlSecTransformCtxDebugDump(&(encCtx->transformCtx), output); if(encCtx->encMethod != NULL) { fprintf(output, "== Encryption Method:\n"); xmlSecTransformDebugDump(encCtx->encMethod, output); } if(encCtx->encKey != NULL) { fprintf(output, "== Encryption Key:\n"); xmlSecKeyDebugDump(encCtx->encKey, output); } if((encCtx->result != NULL) && (xmlSecBufferGetData(encCtx->result) != NULL) && (encCtx->resultBase64Encoded != 0)) { fprintf(output, "== Result - start buffer:\n"); fwrite(xmlSecBufferGetData(encCtx->result), xmlSecBufferGetSize(encCtx->result), 1, output); fprintf(output, "\n== Result - end buffer\n"); } } /** * xmlSecEncCtxDebugXmlDump: * @encCtx: the pointer to processing context. * @output: the pointer to output FILE. * * Prints the debug information about @encCtx to @output in XML format. */ void xmlSecEncCtxDebugXmlDump(xmlSecEncCtxPtr encCtx, FILE* output) { xmlSecAssert(encCtx != NULL); xmlSecAssert(output != NULL); switch(encCtx->mode) { case xmlEncCtxModeEncryptedData: if(encCtx->operation == xmlSecTransformOperationEncrypt) { fprintf(output, "operation == xmlSecTransformOperationEncrypt) { fprintf(output, "\n", (encCtx->resultReplaced) ? "replaced" : "not-replaced" ); fprintf(output, "%08x\n", encCtx->flags); fprintf(output, "%08x\n", encCtx->flags2); fprintf(output, ""); xmlSecPrintXmlString(output, encCtx->id); fprintf(output, ""); fprintf(output, ""); xmlSecPrintXmlString(output, encCtx->type); fprintf(output, ""); fprintf(output, ""); xmlSecPrintXmlString(output, encCtx->mimeType); fprintf(output, ""); fprintf(output, ""); xmlSecPrintXmlString(output, encCtx->encoding); fprintf(output, ""); fprintf(output, ""); xmlSecPrintXmlString(output, encCtx->recipient); fprintf(output, ""); fprintf(output, ""); xmlSecPrintXmlString(output, encCtx->carriedKeyName); fprintf(output, ""); fprintf(output, "\n"); xmlSecKeyInfoCtxDebugXmlDump(&(encCtx->keyInfoReadCtx), output); fprintf(output, "\n"); fprintf(output, "\n"); xmlSecKeyInfoCtxDebugXmlDump(&(encCtx->keyInfoWriteCtx), output); fprintf(output, "\n"); fprintf(output, "\n"); xmlSecTransformCtxDebugXmlDump(&(encCtx->transformCtx), output); fprintf(output, "\n"); if(encCtx->encMethod != NULL) { fprintf(output, "\n"); xmlSecTransformDebugXmlDump(encCtx->encMethod, output); fprintf(output, "\n"); } if(encCtx->encKey != NULL) { fprintf(output, "\n"); xmlSecKeyDebugXmlDump(encCtx->encKey, output); fprintf(output, "\n"); } if((encCtx->result != NULL) && (xmlSecBufferGetData(encCtx->result) != NULL) && (encCtx->resultBase64Encoded != 0)) { fprintf(output, ""); fwrite(xmlSecBufferGetData(encCtx->result), xmlSecBufferGetSize(encCtx->result), 1, output); fprintf(output, "\n"); } switch(encCtx->mode) { case xmlEncCtxModeEncryptedData: if(encCtx->operation == xmlSecTransformOperationEncrypt) { fprintf(output, "\n"); } else { fprintf(output, "\n"); } break; case xmlEncCtxModeEncryptedKey: if(encCtx->operation == xmlSecTransformOperationEncrypt) { fprintf(output, "\n"); } else { fprintf(output, "\n"); } break; } } #endif /* XMLSEC_NO_XMLENC */