BuildRequires: pkgconfig(libsystemd-daemon)
BuildRequires: pkgconfig(vconf)
BuildRequires: pkgconfig(libsystemd-journal)
+BuildRequires: pkgconfig(libxml-2.0)
BuildRequires: boost-devel
Requires: libkey-manager-common = %{version}-%{release}
%{?systemd_requires}
%package -n key-manager-tests
Summary: Internal test for key-manager
Group: Development
+BuildRequires: pkgconfig(libxml-2.0)
Requires: boost-test
Requires: key-manager = %{version}-%{release}
cp tests/testme_ver1.db %{buildroot}/usr/share/ckm-db-test/
cp tests/testme_ver2.db %{buildroot}/usr/share/ckm-db-test/
cp tests/testme_ver3.db %{buildroot}/usr/share/ckm-db-test/
+cp tests/XML_1_okay.xml %{buildroot}/usr/share/ckm-db-test/
+cp tests/XML_1_okay.xsd %{buildroot}/usr/share/ckm-db-test/
+cp tests/XML_1_wrong.xml %{buildroot}/usr/share/ckm-db-test/
+cp tests/XML_1_wrong.xsd %{buildroot}/usr/share/ckm-db-test/
+cp tests/XML_2_structure.xml %{buildroot}/usr/share/ckm-db-test/
mkdir -p %{buildroot}/etc/gumd/userdel.d/
cp data/gumd/10_key-manager.post %{buildroot}/etc/gumd/userdel.d/
%{_datadir}/ckm-db-test/testme_ver1.db
%{_datadir}/ckm-db-test/testme_ver2.db
%{_datadir}/ckm-db-test/testme_ver3.db
+%{_datadir}/ckm-db-test/XML_1_okay.xml
+%{_datadir}/ckm-db-test/XML_1_okay.xsd
+%{_datadir}/ckm-db-test/XML_1_wrong.xml
+%{_datadir}/ckm-db-test/XML_1_wrong.xsd
+%{_datadir}/ckm-db-test/XML_2_structure.xml
%{_bindir}/ckm_so_loader
%files -n key-manager-pam-plugin
libsystemd-daemon
capi-base-common
vconf
+ libxml-2.0
REQUIRED
)
FIND_PACKAGE(Threads REQUIRED)
${KEY_MANAGER_PATH}/service/db-crypto.cpp
${KEY_MANAGER_PATH}/service/ocsp-service.cpp
${KEY_MANAGER_PATH}/service/ocsp-logic.cpp
+ ${KEY_MANAGER_PATH}/initial-values/parser.cpp
${KEY_MANAGER_PATH}/dpl/core/src/assert.cpp
${KEY_MANAGER_PATH}/dpl/db/src/sql_connection.cpp
${KEY_MANAGER_PATH}/dpl/db/src/naive_synchronization_object.cpp
${KEY_MANAGER_PATH}/main
${KEY_MANAGER_PATH}/common
${KEY_MANAGER_PATH}/service
+ ${KEY_MANAGER_PATH}/initial-values
${KEY_MANAGER_PATH}/sqlcipher
${KEY_MANAGER_PATH}/dpl/core/include
${KEY_MANAGER_PATH}/dpl/log/include
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ *
+ *
+ * @file parser.cpp
+ * @author Maciej Karpiuk (m.karpiuk2@samsung.com)
+ * @version 1.0
+ * @brief XML parser class implementation.
+ */
+
+#include <string>
+#include <string.h>
+#include <algorithm>
+#include <exception>
+#include <libxml/parser.h>
+#include <libxml/valid.h>
+#include <libxml/xmlschemas.h>
+#include <parser.h>
+#include <dpl/log/log.h>
+
+using namespace XML;
+
+namespace
+{
+const char * const WHITESPACE = " \n\r\t";
+std::string trim_left(const std::string& s)
+{
+ size_t startpos = s.find_first_not_of(WHITESPACE);
+ return (startpos == std::string::npos) ? "" : s.substr(startpos);
+}
+
+std::string trim_right(const std::string& s)
+{
+ size_t endpos = s.find_last_not_of(WHITESPACE);
+ return (endpos == std::string::npos) ? "" : s.substr(0, endpos+1);
+}
+std::string trim(const std::string& s)
+{
+ return trim_right(trim_left(s));
+}
+}
+
+Parser::Parser(const char *XML_filename)
+ : m_errorCb(0)
+{
+ if(XML_filename)
+ m_XMLfile = XML_filename;
+ memset(&m_saxHandler, 0, sizeof(m_saxHandler));
+ m_saxHandler.startElement = &Parser::StartElement;
+ m_saxHandler.endElement = &Parser::EndElement;
+ m_saxHandler.characters = &Parser::Characters;
+ m_saxHandler.error = &Parser::Error;
+ m_saxHandler.warning = &Parser::Warning;
+}
+Parser::~Parser()
+{
+ xmlCleanupParser();
+}
+
+int Parser::Validate(const char *XSD_schema)
+{
+ if(!XSD_schema) {
+ LogError("no XSD file path given");
+ return ERROR_INVALID_ARGUMENT;
+ }
+
+ int retCode;
+ std::unique_ptr<xmlSchemaParserCtxt, void(*)(xmlSchemaParserCtxtPtr)>
+ parserCtxt(xmlSchemaNewParserCtxt(XSD_schema),
+ [](xmlSchemaParserCtxtPtr ctx){ xmlSchemaFreeParserCtxt(ctx); });
+ if(!parserCtxt) {
+ LogError("XSD file path is invalid");
+ return ERROR_INVALID_ARGUMENT;
+ }
+
+ std::unique_ptr<xmlSchema, void(*)(xmlSchemaPtr)>
+ schema(xmlSchemaParse(parserCtxt.get()),
+ [](xmlSchemaPtr schemaPtr){ xmlSchemaFree(schemaPtr); });
+ if(!schema) {
+ LogError("Parsing XSD file failed");
+ return ERROR_XSD_PARSE_FAILED;
+ }
+
+
+ std::unique_ptr<xmlSchemaValidCtxt, void(*)(xmlSchemaValidCtxtPtr)>
+ validCtxt(xmlSchemaNewValidCtxt(schema.get()),
+ [](xmlSchemaValidCtxtPtr validCtxPtr){ xmlSchemaFreeValidCtxt(validCtxPtr); });
+ if(!validCtxt) {
+ LogError("Internal parser error");
+ return ERROR_INTERNAL;
+ }
+
+ xmlSetStructuredErrorFunc(NULL, NULL);
+ xmlSetGenericErrorFunc(this, &Parser::ErrorValidate);
+ xmlThrDefSetStructuredErrorFunc(NULL, NULL);
+ xmlThrDefSetGenericErrorFunc(this, &Parser::ErrorValidate);
+
+ retCode = xmlSchemaValidateFile(validCtxt.get(), m_XMLfile.c_str(), 0);
+ if(0 != retCode) {
+ LogWarning("Validating XML file failed, ec: " << retCode);
+ retCode = ERROR_XML_VALIDATION_FAILED;
+ }
+ else
+ retCode = SUCCESS;
+
+ return retCode;
+}
+
+int Parser::Parse()
+{
+ if(m_elementListenerMap.empty()) {
+ LogError("Can not parse XML file: no registered element callbacks.");
+ return ERROR_INVALID_ARGUMENT;
+ }
+ int retCode = xmlSAXUserParseFile(&m_saxHandler, this, m_XMLfile.c_str());
+ if(0 != retCode) {
+ LogWarning("Parsing XML file failed, ec: " << retCode);
+ return ERROR_XML_PARSE_FAILED;
+ }
+ // if error detected while parsing
+ if(m_elementListenerMap.empty()) {
+ LogError("Critical error detected while parsing.");
+ return ERROR_INTERNAL;
+ }
+ return SUCCESS;
+}
+
+int Parser::RegisterErrorCb(const ErrorCb newCb)
+{
+ if(m_errorCb) {
+ LogError("Callback already registered!");
+ return ERROR_CALLBACK_PRESENT;
+ }
+ m_errorCb = newCb;
+ return SUCCESS;
+}
+
+int Parser::RegisterElementCb(const char * elementName,
+ const StartCb startCb,
+ const EndCb endCb)
+{
+ if(!elementName)
+ return ERROR_INVALID_ARGUMENT;
+
+ std::string key(elementName);
+
+ if(m_elementListenerMap.find(elementName) != m_elementListenerMap.end()) {
+ LogError("Callback for element " << elementName << " already registered!");
+ return ERROR_CALLBACK_PRESENT;
+ }
+
+ m_elementListenerMap[key] = {startCb, endCb};
+ return SUCCESS;
+}
+
+void Parser::StartElement(const xmlChar *name,
+ const xmlChar **attrs)
+{
+ std::string key(reinterpret_cast<const char*>(name));
+ if(m_elementListenerMap.find(key) == m_elementListenerMap.end())
+ return;
+
+ ElementHandlerPtr newHandler;
+ const ElementListener & current = m_elementListenerMap[key];
+ if(current.startCb)
+ {
+ Attributes attribs;
+ {
+ size_t numAttrs = 0;
+ std::string key;
+ while(attrs && attrs[numAttrs])
+ {
+ const char *attrChr = reinterpret_cast<const char*>(attrs[numAttrs]);
+ if((numAttrs%2)==0)
+ key = std::string(attrChr);
+ else
+ attribs[key] = std::string(attrChr);
+ numAttrs ++;
+ }
+ }
+
+ newHandler = current.startCb();
+ if(newHandler)
+ newHandler->Start(attribs);
+ }
+ // always put a handler, even if it's empty. This will not break
+ // the sequence of queued elements when popping from the queue.
+ m_elementHandlerStack.push(newHandler);
+}
+
+void Parser::EndElement(const xmlChar *name)
+{
+ std::string key(reinterpret_cast<const char*>(name));
+ if(m_elementListenerMap.find(key) == m_elementListenerMap.end())
+ return;
+
+ // this should never ever happen
+ if( m_elementHandlerStack.empty() )
+ throw std::runtime_error("internal error: element queue desynchronized!");
+
+ ElementHandlerPtr ¤tHandler = m_elementHandlerStack.top();
+ if(currentHandler)
+ currentHandler.get()->End();
+
+ const ElementListener & current = m_elementListenerMap[key];
+ if(current.endCb)
+ current.endCb(currentHandler);
+
+ m_elementHandlerStack.pop();
+}
+
+void Parser::Characters(const xmlChar *ch, size_t chLen)
+{
+ std::string chars = trim(std::string(reinterpret_cast<const char*>(ch), chLen));
+ if(chars.empty())
+ return;
+
+ if( !m_elementHandlerStack.empty() )
+ {
+ ElementHandlerPtr ¤tHandler = m_elementHandlerStack.top();
+ if(currentHandler)
+ currentHandler.get()->Characters(chars);
+ }
+}
+
+void Parser::Error(const ErrorType errorType, const char *msg, va_list &args)
+{
+ if(!m_errorCb)
+ return;
+
+ va_list args2;
+ try
+ {
+ va_copy(args2, args);
+ std::vector<char> buf(1 + std::vsnprintf(NULL, 0, msg, args));
+ std::vsnprintf(buf.data(), buf.size(), msg, args2);
+ m_errorCb(errorType, trim(std::string(buf.begin(), buf.end())));
+ }
+ catch(...) {
+ LogError("Error callback throwed an exception.");
+ // if an error handler throwed exception,
+ // do not call further callbacks
+ m_elementListenerMap.clear();
+ }
+ va_end(args2);
+}
+
+//
+// -------------------------- start of static wrappers --------------------------
+//
+void Parser::CallbackHelper(std::function<void (void)> func)
+{
+ try
+ {
+ func();
+ return;
+ }
+ catch(const std::exception &e) {
+ LogError("parser error: " << e.what());
+ if(m_errorCb)
+ m_errorCb(PARSE_ERROR, e.what());
+ }
+ catch(...) {
+ LogError("unknown parser error");
+ if(m_errorCb)
+ m_errorCb(PARSE_ERROR, "unknown parser error");
+ }
+ // raise error flag - unregister listeners
+ m_elementListenerMap.clear();
+}
+void Parser::StartElement(void *userData,
+ const xmlChar *name,
+ const xmlChar **attrs)
+{
+ Parser *parser = static_cast<Parser *>(userData);
+ parser->CallbackHelper([&parser, &name, &attrs] { parser->StartElement(name, attrs); });
+}
+void Parser::EndElement(void *userData,
+ const xmlChar *name)
+{
+ Parser *parser = static_cast<Parser *>(userData);
+ parser->CallbackHelper([&parser, &name] { parser->EndElement(name); });
+}
+void Parser::Characters(void *userData,
+ const xmlChar *ch,
+ int len)
+{
+ Parser *parser = static_cast<Parser *>(userData);
+ parser->CallbackHelper([&parser, &ch, &len] { parser->Characters(ch, static_cast<size_t>(len)); });
+}
+
+void Parser::ErrorValidate(void *userData,
+ const char *msg,
+ ...)
+{
+ va_list args;
+ va_start(args, msg);
+ Parser *parser = static_cast<Parser *>(userData);
+ parser->Error(VALIDATION_ERROR, msg, args);
+ va_end(args);
+}
+
+void Parser::Error(void *userData,
+ const char *msg,
+ ...)
+{
+ va_list args;
+ va_start(args, msg);
+ Parser *parser = static_cast<Parser *>(userData);
+ parser->Error(PARSE_ERROR, msg, args);
+ va_end(args);
+}
+
+void Parser::Warning(void *userData,
+ const char *msg,
+ ...)
+{
+ va_list args;
+ va_start(args, msg);
+ Parser &parser = *(static_cast<Parser *>(userData));
+ parser.Error(PARSE_WARNING, msg, args);
+ va_end(args);
+}
+//
+// -------------------------- end of static wrappers --------------------------
+//
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ *
+ *
+ * @file parser.h
+ * @author Maciej Karpiuk (m.karpiuk2@samsung.com)
+ * @version 1.0
+ * @brief XML parser class.
+ */
+
+#ifndef XML_PARSER_H_
+#define XML_PARSER_H_
+
+#include <map>
+#include <vector>
+#include <string>
+#include <stack>
+#include <functional>
+#include <memory>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+namespace XML
+{
+
+class Parser
+{
+public:
+ enum ErrorCode {
+ SUCCESS = 0,
+ ERROR_UNKNOWN = -1000,
+ ERROR_XML_VALIDATION_FAILED = -1001,
+ ERROR_XSD_PARSE_FAILED = -1002,
+ ERROR_XML_PARSE_FAILED = -1003,
+ ERROR_INVALID_ARGUMENT = -1004,
+ ERROR_CALLBACK_PRESENT = -1005,
+ ERROR_INTERNAL = -1006,
+ ERROR_NO_MEMORY = -1007
+ };
+
+ explicit Parser(const char *XML_filename);
+ virtual ~Parser();
+
+ int Validate(const char *XSD_schema);
+ int Parse();
+
+ enum ErrorType {
+ VALIDATION_ERROR,
+ PARSE_ERROR,
+ PARSE_WARNING
+ };
+ typedef std::function<void (const ErrorType, const std::string &)> ErrorCb;
+ int RegisterErrorCb(const ErrorCb newCb);
+
+ typedef std::map<std::string, std::string> Attributes;
+ class ElementHandler
+ {
+ public:
+ virtual ~ElementHandler() {}
+
+ // methods below may throw std::exception to invalidate the parsing process
+ // and remove all element listeners.
+ // In this case, parsing error code returned to the user after std::exception.
+ virtual void Start(const Attributes &) = 0;
+ virtual void Characters(const std::string & data) = 0;
+ virtual void End() = 0;
+ };
+ typedef std::shared_ptr<ElementHandler> ElementHandlerPtr;
+
+ typedef std::function<ElementHandlerPtr ()> StartCb;
+ typedef std::function<void (const ElementHandlerPtr &)> EndCb;
+ int RegisterElementCb(const char * elementName,
+ const StartCb startCb,
+ const EndCb endCb);
+
+protected:
+ void StartElement(const xmlChar *name,
+ const xmlChar **attrs);
+ void EndElement(const xmlChar *name);
+ void Characters(const xmlChar *ch, size_t chLen);
+ void Error(const ErrorType errorType, const char *msg, va_list &);
+
+private:
+ static void StartElement(void *userData,
+ const xmlChar *name,
+ const xmlChar **attrs);
+ static void EndElement(void *userData,
+ const xmlChar *name);
+ static void Characters(void *userData,
+ const xmlChar *ch,
+ int len);
+ static void ErrorValidate(void *userData,
+ const char *msg,
+ ...);
+ static void Error(void *userData,
+ const char *msg,
+ ...);
+ static void Warning(void *userData,
+ const char *msg,
+ ...);
+
+private:
+ xmlSAXHandler m_saxHandler;
+ std::string m_XMLfile;
+ ErrorCb m_errorCb;
+
+ struct ElementListener
+ {
+ StartCb startCb;
+ EndCb endCb;
+ };
+ std::map<std::string, ElementListener> m_elementListenerMap;
+ std::stack<ElementHandlerPtr> m_elementHandlerStack;
+
+ void CallbackHelper(std::function<void (void)> func);
+};
+
+}
+#endif /* XML_PARSER_H_ */
+PKG_CHECK_MODULES(KEY_MANAGER_TEST_DEP
+ libxml-2.0
+ REQUIRED
+ )
+
FIND_PACKAGE(Threads REQUIRED)
ADD_DEFINITIONS( "-DBOOST_TEST_DYN_LINK" )
SET(KEY_MANAGER_TEST_MERGED_SRC ${PROJECT_SOURCE_DIR}/tests)
INCLUDE_DIRECTORIES(
+ ${KEY_MANAGER_DEP_INCLUDE_DIRS}
${KEY_MANAGER_PATH}/dpl/db/include
${KEY_MANAGER_PATH}/dpl/core/include
${KEY_MANAGER_PATH}/dpl/log/include
${KEY_MANAGER_PATH}/sqlcipher
${KEY_MANAGER_PATH}/service
+ ${KEY_MANAGER_PATH}/initial-values
${KEY_MANAGER_PATH}/main
${KEY_MANAGER_PATH}/common/
${KEY_MANAGER_PATH}/client-async/
${KEY_MANAGER_TEST_MERGED_SRC}/test_descriptor-set.cpp
${KEY_MANAGER_TEST_MERGED_SRC}/test_comm-manager.cpp
${KEY_MANAGER_TEST_MERGED_SRC}/test_serialization.cpp
+ ${KEY_MANAGER_TEST_MERGED_SRC}/test_xml-parser.cpp
${KEY_MANAGER_PATH}/service/db-crypto.cpp
${KEY_MANAGER_PATH}/service/key-provider.cpp
+ ${KEY_MANAGER_PATH}/initial-values/parser.cpp
${KEY_MANAGER_PATH}/client-async/descriptor-set.cpp
${KEY_MANAGER_PATH}/dpl/core/src/assert.cpp
${KEY_MANAGER_PATH}/dpl/core/src/colors.cpp
TARGET_LINK_LIBRARIES(${TARGET_TEST_MERGED}
${TARGET_KEY_MANAGER_COMMON}
${CMAKE_THREAD_LIBS_INIT}
+ ${KEY_MANAGER_DEP_LIBRARIES}
boost_unit_test_framework
-ldl
)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<InitialValues version="0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="initial_values.xsd ">
+ <Key name="key1" type="RSA_PRV" password="123">
+ <PEM>
+ -----BEGIN PUBLIC KEY-----
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2b1bXDa+S8/MGWnMkru4
+ T4tUddtZNi0NVjQn9RFH1NMa220GsRhRO56F77FlSVFKfSfVZKIiWg6C+DVCkcLf
+ zXJ/Z0pvwOQYBAqVMFjV6efQGN0JzJ1Unu7pPRiZl7RKGEI+cyzzrcDyrLLrQ2W7
+ 0ZySkNEOv6Frx9JgC5NExuYY4lk2fQQa38JXiZkfyzif2em0px7mXbyf5LjccsKq
+ v1e+XLtMsL0ZefRcqsP++NzQAI8fKX7WBT+qK0HJDLiHrKOTWYzx6CwJ66LD/vvf
+ j55xtsKDLVDbsotvf8/m6VLMab+vqKk11TP4tq6yo0mwyTADvgl1zowQEO9I1W6o
+ zQIDAQAB
+ -----END PUBLIC KEY-----
+ </PEM>
+ </Key>
+ <Cert exportable="true" name="cert1">
+ <DER>
+ MIIEgDCCA2igAwIBAgIIcjtBYJGQtOAwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+ BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
+ cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwNTIyMTEyOTQyWhcNMTQwODIwMDAwMDAw
+ WjBtMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
+ TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEcMBoGA1UEAwwTYWNj
+ rHva8A==
+ </DER>
+ </Cert>
+ <Data name="data1">
+ <ASCII>
+ My secret data
+ </ASCII>
+ </Data>
+ <Key name="aes1" type="AES">
+ <Base64>
+ MIIEgDCCA2igAwIBAgIIcjtBYJGQtOAwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+ </Base64>
+ <Permission accessor="web_app1"/>
+ <Permission accessor="web_app2"/>
+ </Key>
+</InitialValues>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="InitialValues" type="InitialValuesType"></xsd:element>
+
+ <xsd:complexType name="InitialValuesType">
+ <xsd:sequence>
+ <xsd:choice maxOccurs="unbounded" minOccurs="1">
+ <xsd:element name="Data" type="DataType"
+ maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ <xsd:element name="Key" type="KeyType"
+ maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ <xsd:element name="Cert" type="CertType"
+ maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ </xsd:choice>
+ </xsd:sequence>
+ <xsd:attribute name="version" type="xsd:int" use="required"></xsd:attribute>
+ </xsd:complexType>
+
+ <xsd:complexType name="ObjectType">
+ <xsd:attribute name="name" use="required">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:minLength value="1"></xsd:minLength>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ <xsd:attribute name="password" use="optional"
+ type="xsd:string">
+ </xsd:attribute>
+ <xsd:attribute name="exportable" use="optional"
+ default="false">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:boolean"></xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ </xsd:complexType>
+
+ <xsd:complexType name="KeyType">
+ <xsd:complexContent>
+ <xsd:extension base="ObjectType">
+ <xsd:sequence>
+ <xsd:choice maxOccurs="1" minOccurs="1">
+ <xsd:element name="PEM"
+ type="EncodingPemType" maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ <xsd:element name="DER"
+ type="EncodingDerType" maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ <xsd:element name="Base64"
+ type="EncodingRawType" maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ </xsd:choice>
+ <xsd:element name="Permission" type="PermissionType" maxOccurs="unbounded" minOccurs="0"></xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="type">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="RSA_PRV"></xsd:enumeration>
+ <xsd:enumeration value="RSA_PUB"></xsd:enumeration>
+ <xsd:enumeration value="ECDSA_PRV"></xsd:enumeration>
+ <xsd:enumeration value="ECDSA_PUB"></xsd:enumeration>
+ <xsd:enumeration value="DSA_PRV"></xsd:enumeration>
+ <xsd:enumeration value="DSA_PUB"></xsd:enumeration>
+ <xsd:enumeration value="AES"></xsd:enumeration>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="CertType">
+ <xsd:complexContent>
+ <xsd:extension base="ObjectType">
+ <xsd:sequence>
+ <xsd:choice maxOccurs="1" minOccurs="1">
+ <xsd:element name="PEM" type="EncodingPemType"
+ maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ <xsd:element name="DER"
+ type="EncodingDerType" maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ </xsd:choice>
+ <xsd:element name="Permission" type="PermissionType" maxOccurs="unbounded" minOccurs="0"></xsd:element>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="DataType">
+ <xsd:complexContent>
+ <xsd:extension base="ObjectType">
+ <xsd:sequence>
+ <xsd:choice maxOccurs="1" minOccurs="1">
+ <xsd:element name="ASCII"
+ type="EncodingAsciiType" maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ <xsd:element name="Base64"
+ type="EncodingRawType" maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ </xsd:choice>
+ <xsd:element name="Permission" type="PermissionType" maxOccurs="unbounded" minOccurs="0"></xsd:element>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:simpleType name="EncodingAsciiType">
+ <xsd:restriction base="xsd:string"></xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="EncodingDerType">
+ <xsd:restriction base="xsd:string"></xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="EncodingPemType">
+ <xsd:restriction base="xsd:string"></xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="EncodingRawType">
+ <xsd:restriction base="xsd:string"></xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:complexType name="PermissionType">
+ <xsd:attribute name="accessor" type="xsd:string"></xsd:attribute>
+ </xsd:complexType>
+
+</xsd:schema>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<InitialValues version="0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="initial_values.xsd ">
+ <Key name="key1" type="RSA_PRV" password="123">
+ <PEM>
+ -----BEGIN PUBLIC KEY-----
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2b1bXDa+S8/MGWnMkru4
+ T4tUddtZNi0NVjQn9RFH1NMa220GsRhRO56F77FlSVFKfSfVZKIiWg6C+DVCkcLf
+ zXJ/Z0pvwOQYBAqVMFjV6efQGN0JzJ1Unu7pPRiZl7RKGEI+cyzzrcDyrLLrQ2W7
+ 0ZySkNEOv6Frx9JgC5NExuYY4lk2fQQa38JXiZkfyzif2em0px7mXbyf5LjccsKq
+ v1e+XLtMsL0ZefRcqsP++NzQAI8fKX7WBT+qK0HJDLiHrKOTWYzx6CwJ66LD/vvf
+ j55xtsKDLVDbsotvf8/m6VLMab+vqKk11TP4tq6yo0mwyTADvgl1zowQEO9I1W6o
+ zQIDAQAB
+ -----END PUBLIC KEY-----
+ </PEM>
+ </HERE_GOES_AN_ERROR>
+ <Cert exportable="true" name="cert1">
+ <DER>
+ MIIEgDCCA2igAwIBAgIIcjtBYJGQtOAwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+ BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
+ cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwNTIyMTEyOTQyWhcNMTQwODIwMDAwMDAw
+ WjBtMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
+ TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEcMBoGA1UEAwwTYWNj
+ rHva8A==
+ </DER>
+ </Cert>
+ <Data name="data1">
+ <ASCII>
+ My secret data
+ </ASCII>
+ </Data>
+ <Key name="aes1" type="AES">
+ <Base64>
+ MIIEgDCCA2igAwIBAgIIcjtBYJGQtOAwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+ </Base64>
+ <Permission accessor="web_app1"/>
+ <Permission accessor="web_app2"/>
+ </Key>
+</InitialValues>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="InitialValues" type="InitialValuesType"></xsd:element>
+
+ <xsd:complexType name="InitialValuesType">
+ <xsd:sequence>
+ <xsd:choice maxOccurs="unbounded" minOccurs="1">
+ <xsd:element name="Data" type="DataType"
+ maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ <xsd:element name="Key" type="KeyType"
+ maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ <xsd:element name="Cert" type="CertType"
+ maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ </xsd:choice>
+<!-- </xsd:sequence> -->
+ <xsd:attribute name="version" type="xsd:int" use="required"></xsd:attribute>
+ </xsd:complexType>
+
+ <xsd:complexType name="ObjectType">
+ <xsd:attribute name="name" use="required">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:minLength value="1"></xsd:minLength>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ <xsd:attribute name="password" use="optional"
+ type="xsd:string">
+ </xsd:attribute>
+ <xsd:attribute name="exportable" use="optional"
+ default="false">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:boolean"></xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ </xsd:complexType>
+
+ <xsd:complexType name="KeyType">
+ <xsd:complexContent>
+ <xsd:extension base="ObjectType">
+ <xsd:sequence>
+ <xsd:choice maxOccurs="1" minOccurs="1">
+ <xsd:element name="PEM"
+ type="EncodingPemType" maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ <xsd:element name="DER"
+ type="EncodingDerType" maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ <xsd:element name="Base64"
+ type="EncodingRawType" maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ </xsd:choice>
+ <xsd:element name="Permission" type="PermissionType" maxOccurs="unbounded" minOccurs="0"></xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="type">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="RSA_PRV"></xsd:enumeration>
+ <xsd:enumeration value="RSA_PUB"></xsd:enumeration>
+ <xsd:enumeration value="ECDSA_PRV"></xsd:enumeration>
+ <xsd:enumeration value="ECDSA_PUB"></xsd:enumeration>
+ <xsd:enumeration value="DSA_PRV"></xsd:enumeration>
+ <xsd:enumeration value="DSA_PUB"></xsd:enumeration>
+ <xsd:enumeration value="AES"></xsd:enumeration>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="CertType">
+ <xsd:complexContent>
+ <xsd:extension base="ObjectType">
+ <xsd:sequence>
+ <xsd:choice maxOccurs="1" minOccurs="1">
+ <xsd:element name="PEM" type="EncodingPemType"
+ maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ <xsd:element name="DER"
+ type="EncodingDerType" maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ </xsd:choice>
+ <xsd:element name="Permission" type="PermissionType" maxOccurs="unbounded" minOccurs="0"></xsd:element>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="DataType">
+ <xsd:complexContent>
+ <xsd:extension base="ObjectType">
+ <xsd:sequence>
+ <xsd:choice maxOccurs="1" minOccurs="1">
+ <xsd:element name="ASCII"
+ type="EncodingAsciiType" maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ <xsd:element name="Base64"
+ type="EncodingRawType" maxOccurs="1" minOccurs="1">
+ </xsd:element>
+ </xsd:choice>
+ <xsd:element name="Permission" type="PermissionType" maxOccurs="unbounded" minOccurs="0"></xsd:element>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:simpleType name="EncodingAsciiType">
+ <xsd:restriction base="xsd:string"></xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="EncodingDerType">
+ <xsd:restriction base="xsd:string"></xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="EncodingPemType">
+ <xsd:restriction base="xsd:string"></xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="EncodingRawType">
+ <xsd:restriction base="xsd:string"></xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:complexType name="PermissionType">
+ <xsd:attribute name="accessor" type="xsd:string"></xsd:attribute>
+ </xsd:complexType>
+
+</xsd:schema>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<StructureTest version="0">
+<Add>1</Add>
+<Add powerFactor="4">2</Add>
+<Add>3</Add>
+<Add>5</Add>
+<Add dummyAttr="123">7</Add>
+<Add>11</Add>
+<Add>13</Add>
+<Multiply>
+ -10
+</Multiply>
+<Add>17</Add>
+<Add>19</Add>
+<Div>
+
+
+ -2</Div>
+<ExpectedSum>
+ 262
+</ExpectedSum>
+</StructureTest>
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ *
+ *
+ * @file test_xml-parser.cpp
+ * @author Maciej Karpiuk (m.karpiuk2@samsung.com)
+ * @version 1.0
+ * @brief XML parser tests.
+ */
+
+#include <vector>
+#include <boost/test/unit_test.hpp>
+#include <parser.h>
+
+using namespace XML;
+
+namespace
+{
+const char *XML_1_okay = "XML_1_okay.xml";
+const char *XSD_1_okay = "XML_1_okay.xsd";
+const char *XML_1_wrong = "XML_1_wrong.xml";
+const char *XSD_1_wrong = "XML_1_wrong.xsd";
+const char *XML_2_structure = "XML_2_structure.xml";
+const char *XML_3_structure = "XML_3_structure.xml";
+
+std::string format_test_path(const char *file)
+{
+ return std::string("/usr/share/ckm-db-test/") + std::string(file);
+}
+
+bool startCallbackFlag = false;
+XML::Parser::ElementHandlerPtr dummyStartCallback()
+{
+ startCallbackFlag = true;
+ // return empty pointer
+ return XML::Parser::ElementHandlerPtr();
+}
+bool endCallbackFlag = false;
+void dummyEndCallback(const XML::Parser::ElementHandlerPtr &)
+{
+ endCallbackFlag = true;
+}
+}
+
+BOOST_AUTO_TEST_SUITE(XML_PARSER_TEST)
+
+BOOST_AUTO_TEST_CASE(XmlParserTest_wrong_argument)
+{
+ XML::Parser parser(0);
+ BOOST_REQUIRE(Parser::ErrorCode::ERROR_INVALID_ARGUMENT == parser.Validate(0));
+
+ // no listeners
+ BOOST_REQUIRE(Parser::ErrorCode::ERROR_INVALID_ARGUMENT == parser.Parse());
+
+ BOOST_REQUIRE(Parser::ErrorCode::SUCCESS == parser.RegisterElementCb("Key", dummyStartCallback, dummyEndCallback));
+ BOOST_REQUIRE(Parser::ErrorCode::ERROR_XML_PARSE_FAILED == parser.Parse());
+}
+
+BOOST_AUTO_TEST_CASE(XmlParserTest_no_XML_file)
+{
+ XML::Parser parser(format_test_path("i-am-not-here").c_str());
+ BOOST_REQUIRE(Parser::ErrorCode::ERROR_XML_VALIDATION_FAILED == parser.Validate(format_test_path(XSD_1_okay).c_str()));
+}
+
+BOOST_AUTO_TEST_CASE(XmlParserTest_XML1_correct_verify)
+{
+ XML::Parser parser(format_test_path(XML_1_okay).c_str());
+ BOOST_REQUIRE(0 == parser.Validate(format_test_path(XSD_1_okay).c_str()));
+}
+
+BOOST_AUTO_TEST_CASE(XmlParserTest_XML1_wrong_verify)
+{
+ XML::Parser parser(format_test_path(XML_1_wrong).c_str());
+ BOOST_REQUIRE(Parser::ErrorCode::ERROR_XML_VALIDATION_FAILED == parser.Validate(format_test_path(XSD_1_okay).c_str()));
+}
+
+BOOST_AUTO_TEST_CASE(XmlParserTest_XML1_wrong_schema)
+{
+ XML::Parser parser(format_test_path(XML_1_okay).c_str());
+ BOOST_REQUIRE(Parser::ErrorCode::ERROR_XSD_PARSE_FAILED == parser.Validate(format_test_path(XSD_1_wrong).c_str()));
+}
+
+BOOST_AUTO_TEST_CASE(XmlParserTest_XML1_correct_parse_incorrect_callbacks)
+{
+ XML::Parser parser(format_test_path(XML_1_okay).c_str());
+ BOOST_REQUIRE(0 == parser.Validate(format_test_path(XSD_1_okay).c_str()));
+
+ BOOST_REQUIRE(Parser::ErrorCode::SUCCESS == parser.RegisterElementCb("Data", NULL, NULL));
+ BOOST_REQUIRE(Parser::ErrorCode::SUCCESS == parser.Parse());
+}
+
+BOOST_AUTO_TEST_CASE(XmlParserTest_XML1_correct_parse)
+{
+ XML::Parser parser(format_test_path(XML_1_okay).c_str());
+ BOOST_REQUIRE(0 == parser.Validate(format_test_path(XSD_1_okay).c_str()));
+
+ BOOST_REQUIRE(Parser::ErrorCode::SUCCESS == parser.RegisterElementCb("Key", dummyStartCallback, NULL));
+ BOOST_REQUIRE(Parser::ErrorCode::SUCCESS == parser.RegisterElementCb("Cert", NULL, dummyEndCallback));
+ startCallbackFlag = false;
+ endCallbackFlag = false;
+ BOOST_REQUIRE(Parser::ErrorCode::SUCCESS == parser.Parse());
+ BOOST_REQUIRE(startCallbackFlag == true);
+ BOOST_REQUIRE(endCallbackFlag == true);
+}
+
+
+class StructureTest
+{
+public:
+ class ExpectedSumHandler : public XML::Parser::ElementHandler
+ {
+ public:
+ ExpectedSumHandler() : m_value(0) {}
+
+ virtual void Start(const XML::Parser::Attributes &) {}
+ virtual void Characters(const std::string &data) {
+ m_value = atoi(data.c_str());
+ }
+ virtual void End() {}
+
+ int getSum() const {
+ return m_value;
+ }
+
+ protected:
+ int m_value;
+ };
+
+ class MathHandler : public XML::Parser::ElementHandler
+ {
+ public:
+ MathHandler() : m_valueSet(false), m_powerFactor(1) {}
+
+ virtual void Start(const XML::Parser::Attributes &attr) {
+ const auto & it = attr.find("powerFactor");
+ if(it != attr.end())
+ m_powerFactor = atoi(it->second.c_str());
+ }
+ virtual void Characters(const std::string &data) {
+ m_value = pow(atoi(data.c_str()), m_powerFactor);
+ m_valueSet = true;
+ }
+ virtual void End() {}
+
+ virtual int compute(int prevVal) = 0;
+
+ protected:
+ bool m_valueSet;
+ int m_value;
+ int m_powerFactor;
+ };
+ class AddHandler : public MathHandler
+ {
+ public:
+ virtual int compute(int prevVal) {
+ if( !m_valueSet )
+ return prevVal;
+
+ return prevVal + m_value;
+ }
+ };
+
+ class MultiplyHandler : public MathHandler
+ {
+ public:
+ virtual int compute(int prevVal) {
+ if( !m_valueSet )
+ return prevVal;
+
+ return prevVal * m_value;
+ }
+ };
+
+ class DivHandler : public MathHandler
+ {
+ public:
+ virtual int compute(int prevVal) {
+ if( !m_valueSet )
+ return prevVal;
+
+ if(m_value == 0)
+ return prevVal;
+ return prevVal / m_value;
+ }
+ };
+
+ StructureTest(const char *filename) : m_parser(filename), m_sum(0), m_expectedSum(0)
+ {
+ m_parser.RegisterErrorCb(StructureTest::Error);
+ m_parser.RegisterElementCb("Add",
+ [this]() -> XML::Parser::ElementHandlerPtr
+ {
+ return std::make_shared<AddHandler>();
+ },
+ [this](const XML::Parser::ElementHandlerPtr & element)
+ {
+ // add computation
+ if(element)
+ {
+ MathHandler *mathElement = reinterpret_cast<MathHandler*>(element.get());
+ m_sum = mathElement->compute(m_sum);
+ }
+ });
+ m_parser.RegisterElementCb("Multiply",
+ [this]() -> XML::Parser::ElementHandlerPtr
+ {
+ return std::make_shared<MultiplyHandler>();
+ },
+ [this](const XML::Parser::ElementHandlerPtr &element)
+ {
+ // multiply computation
+ if(element)
+ {
+ MathHandler *mathElement = reinterpret_cast<MathHandler*>(element.get());
+ m_sum = mathElement->compute(m_sum);
+ }
+ });
+ m_parser.RegisterElementCb("Div",
+ [this]() -> XML::Parser::ElementHandlerPtr
+ {
+ return std::make_shared<DivHandler>();
+ },
+ [this](const XML::Parser::ElementHandlerPtr &element)
+ {
+ // division computation
+ if(element)
+ {
+ MathHandler *mathElement = reinterpret_cast<MathHandler*>(element.get());
+ m_sum = mathElement->compute(m_sum);
+ }
+ });
+ m_parser.RegisterElementCb("ExpectedSum",
+ [this]() -> XML::Parser::ElementHandlerPtr
+ {
+ return std::make_shared<ExpectedSumHandler>();
+ },
+ [this](const XML::Parser::ElementHandlerPtr &element)
+ {
+ if(element)
+ {
+ ExpectedSumHandler *sumElement = reinterpret_cast<ExpectedSumHandler*>(element.get());
+ m_expectedSum = sumElement->getSum();
+ }
+ });
+ }
+
+ static void Error(const Parser::ErrorType /*errorType*/,
+ const std::string & log_msg)
+ {
+ BOOST_FAIL(log_msg);
+ }
+
+ int Parse()
+ {
+ return m_parser.Parse();
+ }
+
+ int getSum() const {
+ return m_sum;
+ }
+ int getExpectedSum() const {
+ return m_expectedSum;
+ }
+private:
+ XML::Parser m_parser;
+ int m_sum;
+ int m_expectedSum;
+};
+
+BOOST_AUTO_TEST_CASE(XmlParserTest_XML2_structure)
+{
+ StructureTest parser(format_test_path(XML_2_structure).c_str());
+ BOOST_REQUIRE(0 == parser.Parse());
+ BOOST_REQUIRE_MESSAGE(parser.getSum() == parser.getExpectedSum(),
+ "got sum: " << parser.getSum() << " while expected: " << parser.getExpectedSum());
+}
+
+BOOST_AUTO_TEST_SUITE_END()