2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file XmlsecAdapter.cpp
18 * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
25 #include <libxml/tree.h>
26 #include <libxml/xmlmemory.h>
27 #include <libxml/parser.h>
29 #ifndef XMLSEC_NO_XSLT
30 #include <libxslt/xslt.h>
31 #endif /* XMLSEC_NO_XSLT */
33 #include <xmlsec/xmlsec.h>
34 #include <xmlsec/xmltree.h>
35 #include <xmlsec/xmldsig.h>
36 #include <xmlsec/crypto.h>
37 #include <xmlsec/io.h>
38 #include <xmlsec/keyinfo.h>
39 #include <xmlsec/errors.h>
41 #include <dpl/assert.h>
42 #include <dpl/log/log.h>
44 #include <vcore/XmlsecAdapter.h>
46 #include <vcore/ValidatorCommon.h>
48 #include <dpl/singleton_impl.h>
49 IMPLEMENT_SINGLETON(ValidationCore::XmlSec)
54 FileWrapper(void *argFile, bool argReleased)
56 , released(argReleased)
62 } // anonymous namespace
64 namespace ValidationCore {
65 VC_DECLARE_DELETER(xmlSecKeysMngr, xmlSecKeysMngrDestroy)
67 static const char* DIGEST_MD5 = "md5";
69 std::string XmlSec::s_prefixPath;
71 int XmlSec::fileMatchCallback(const char *filename)
73 std::string path = s_prefixPath + filename;
74 return xmlFileMatch(path.c_str());
77 void* XmlSec::fileOpenCallback(const char *filename)
79 std::string path = s_prefixPath + filename;
81 // LogDebug("Xmlsec opening : " << path);
82 return new FileWrapper(xmlFileOpen(path.c_str()),false);
85 int XmlSec::fileReadCallback(void *context,
89 FileWrapper *fw = static_cast<FileWrapper*>(context);
93 int output = xmlFileRead(fw->file, buffer, len);
96 xmlFileClose(fw->file);
101 int XmlSec::fileCloseCallback(void *context)
103 FileWrapper *fw = static_cast<FileWrapper*>(context);
105 if (!(fw->released)) {
106 output = xmlFileClose(fw->file);
112 void XmlSec::fileExtractPrefix(XmlSecContext *context)
114 if (!(context->workingDirectory.empty())) {
115 s_prefixPath = context->workingDirectory;
119 s_prefixPath = context->signatureFile;
120 size_t pos = s_prefixPath.rfind('/');
121 if (pos == std::string::npos) {
122 s_prefixPath.clear();
124 s_prefixPath.erase(pos + 1, std::string::npos);
128 void LogDebugPrint(const char* file, int line, const char* func,
129 const char* errorObject, const char* errorSubject,
130 int reason, const char* msg)
133 snprintf(total, sizeof(total), "[%s:%d][%s] : [%s] : [%s] : [%s]", file, line, func, errorObject, errorSubject, msg);
137 fprintf(stderr, "## [validate error]: %s\n", total);
138 LogError(" " << total);
142 LogDebug(" " << total);
147 m_initialized(false),
149 m_partialHash(false),
153 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
154 xmlSubstituteEntitiesDefault(1);
155 #ifndef XMLSEC_NO_XSLT
156 xmlIndentTreeOutput = 1;
159 if (xmlSecInit() < 0) {
160 LogError("Xmlsec initialization failed.");
161 ThrowMsg(Exception::InternalError, "Xmlsec initialization failed.");
164 if (xmlSecCheckVersion() != 1) {
166 LogError("Loaded xmlsec library version is not compatible.");
167 ThrowMsg(Exception::InternalError,
168 "Loaded xmlsec library version is not compatible.");
171 #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
172 if (xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
175 "Error: unable to load default xmlsec-crypto library. Make sure "
176 "that you have it installed and check shared libraries path "
177 "(LD_LIBRARY_PATH) envornment variable.");
178 ThrowMsg(Exception::InternalError,
179 "Unable to load default xmlsec-crypto library.");
183 if (xmlSecCryptoAppInit(NULL) < 0) {
185 LogError("Crypto initialization failed.");
186 ThrowMsg(Exception::InternalError, "Crypto initialization failed.");
189 if (xmlSecCryptoInit() < 0) {
190 xmlSecCryptoAppShutdown();
192 LogError("Xmlsec-crypto initialization failed.");
193 ThrowMsg(Exception::InternalError,
194 "Xmlsec-crypto initialization failed.");
197 m_initialized = true;
200 void XmlSec::deinitialize(void)
202 Assert(m_initialized);
204 /* Shutdown xmlsec-crypto library */
205 xmlSecCryptoShutdown();
207 /* Shutdown crypto library */
208 xmlSecCryptoAppShutdown();
210 /* Shutdown xmlsec library */
213 /* Shutdown libxslt/libxml */
214 #ifndef XMLSEC_NO_XSLT
215 xsltCleanupGlobals();
216 #endif /* XMLSEC_NO_XSLT */
218 s_prefixPath.clear();
219 m_initialized = false;
225 m_partialHash = false;
231 XmlSec::Result XmlSec::validateFile(XmlSecContext *context,
232 xmlSecKeysMngrPtr mngr)
234 xmlDocPtr doc = NULL;
235 xmlNodePtr node = NULL;
236 xmlSecDSigCtxPtr dsigCtx = NULL;
239 fileExtractPrefix(context);
240 LogDebug("Prefix path : " << s_prefixPath);
242 xmlSecIOCleanupCallbacks();
244 xmlSecIORegisterCallbacks(
251 doc = xmlParseFile(context->signatureFile.c_str());
252 if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)) {
253 LogWarning("Unable to parse file " << context->signatureFile);
257 /* find start node */
258 node = xmlSecFindNode(xmlDocGetRootElement(
259 doc), xmlSecNodeSignature, xmlSecDSigNs);
261 LogWarning("Start node not found in " << context->signatureFile);
265 /* create signature context */
266 dsigCtx = xmlSecDSigCtxCreate(mngr);
267 if (dsigCtx == NULL) {
268 LogError("Failed to create signature context.");
272 if (context->allowBrokenChain) {
273 dsigCtx->keyInfoReadCtx.flags |=
274 XMLSEC_KEYINFO_FLAGS_ALLOW_BROKEN_CHAIN;
277 if (context->validationTime) {
278 LogDebug("Setting validation time.");
279 dsigCtx->keyInfoReadCtx.certsVerificationTime = context->validationTime;
282 if( m_noHash == true || m_partialHash == true ) {
283 LogDebug("SignatureEx start >> ");
284 if( m_pList == NULL ) {
285 LogWarning("## [validate]: uriList does not exist" );
286 fprintf(stderr, "## [validate]: uriList does not exist\n");
287 res = xmlSecDSigCtxVerifyEx(dsigCtx, node, 1, NULL);
294 LogWarning("## [validate]: uriList does not exist" );
295 fprintf(stderr, "## [validate]: uriList does not exist\n");
303 std::list<std::string>::const_iterator itr = m_pList->begin();
304 std::string tmpString;
308 for(; itr != m_pList->end(); ++itr) {
310 uri = (char*)tmpString.c_str();
312 pList[i] = (char*)malloc(len + 1);
313 memcpy(pList[i], uri, len);
314 pList[i][len] = '\0';
315 fprintf(stderr, "## [validate]: uriList[%d] = %s\n", i, pList[i]);
320 res = xmlSecDSigCtxVerifyEx(dsigCtx, node, 0, (void*)pList);
322 while(pList[i] != NULL) {
329 LogError("SignatureEx verify error.");
330 fprintf(stderr, "## [validate error]: SignatureEx verify error\n");
335 LogDebug("Signature start >> ");
337 /* Verify signature */
338 if (xmlSecDSigCtxVerify(dsigCtx, node) < 0) {
339 LogError("Signature verify error.");
340 fprintf(stderr, "## [validate error]: Signature verify error\n");
346 if (dsigCtx->keyInfoReadCtx.flags2 &
347 XMLSEC_KEYINFO_ERROR_FLAGS_BROKEN_CHAIN) {
348 LogWarning("XMLSEC_KEYINFO_FLAGS_ALLOW_BROKEN_CHAIN was set to true!");
349 LogWarning("Signature contains broken chain!");
350 context->errorBrokenChain = true;
353 /* print verification result to stdout */
354 if (dsigCtx->status == xmlSecDSigStatusSucceeded) {
355 LogDebug("Signature is OK");
358 LogDebug("Signature is INVALID");
363 if (dsigCtx->c14nMethod && dsigCtx->c14nMethod->id &&
364 dsigCtx->c14nMethod->id->name) {
365 // LogInfo("Canonicalization method: " << (reinterpret_cast<const char *>(dsigCtx->c14nMethod->id->name)).c_str());
368 size = xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences));
369 for (int i = 0; i < size; ++i) {
370 xmlSecDSigReferenceCtxPtr dsigRefCtx =
371 (xmlSecDSigReferenceCtxPtr)xmlSecPtrListGetItem(&(dsigCtx->
372 signedInfoReferences),
374 if (dsigRefCtx && dsigRefCtx->uri) {
375 if (dsigRefCtx->digestMethod && dsigRefCtx->digestMethod->id &&
376 dsigRefCtx->digestMethod->id->name) {
377 const char* pDigest =
378 reinterpret_cast<const char *>(dsigRefCtx->digestMethod->id
380 std::string strDigest(pDigest);
381 /*LogInfo("reference digest method: " << (reinterpret_cast<const char *>(dsigRefCtx->digestMethod->id->name)).c_str());*/
382 if (strDigest == DIGEST_MD5) {
383 LogWarning("MD5 digest method used! Please use sha");
388 context->referenceSet.insert(std::string(reinterpret_cast<char *>(
396 m_partialHash = false;
399 if (dsigCtx != NULL) {
400 xmlSecDSigCtxDestroy(dsigCtx);
408 return ERROR_INVALID_SIGNATURE;
413 void XmlSec::loadDERCertificateMemory(XmlSecContext *context,
414 xmlSecKeysMngrPtr mngr)
416 unsigned char *derCertificate = NULL;
417 int size = i2d_X509(context->certificatePtr->getX509(), &derCertificate);
419 if (!derCertificate) {
420 LogError("Failed during x509 conversion to der format.");
421 ThrowMsg(Exception::InternalError,
422 "Failed during x509 conversion to der format.");
425 if (xmlSecCryptoAppKeysMngrCertLoadMemory(mngr,
428 xmlSecKeyDataFormatDer,
429 xmlSecKeyDataTypeTrusted) < 0) {
430 OPENSSL_free(derCertificate);
431 LogError("Failed to load der certificate from memory.");
432 ThrowMsg(Exception::InternalError,
433 "Failed to load der certificate from memory.");
436 OPENSSL_free(derCertificate);
439 void XmlSec::loadPEMCertificateFile(XmlSecContext *context,
440 xmlSecKeysMngrPtr mngr)
442 if (xmlSecCryptoAppKeysMngrCertLoad(mngr,
443 context->certificatePath.c_str(),
444 xmlSecKeyDataFormatPem,
445 xmlSecKeyDataTypeTrusted) < 0) {
446 LogError("Failed to load PEM certificate from file.");
447 ThrowMsg(Exception::InternalError,
448 "Failed to load PEM certificate from file.");
452 XmlSec::Result XmlSec::validate(XmlSecContext *context)
455 Assert(!(context->signatureFile.empty()));
456 Assert(context->certificatePtr.get() || !(context->certificatePath.empty()));
458 xmlSecErrorsSetCallback(LogDebugPrint);
460 if (!m_initialized) {
461 LogError("XmlSec is not initialized.");
462 ThrowMsg(Exception::InternalError, "XmlSec is not initialized");
465 AutoPtr<xmlSecKeysMngr> mngr(xmlSecKeysMngrCreate());
468 LogError("Failed to create keys manager.");
469 ThrowMsg(Exception::InternalError, "Failed to create keys manager.");
472 if (xmlSecCryptoAppDefaultKeysMngrInit(mngr.get()) < 0) {
473 LogError("Failed to initialize keys manager.");
474 ThrowMsg(Exception::InternalError, "Failed to initialize keys manager.");
476 context->referenceSet.clear();
478 if (context->certificatePtr.get()) {
479 loadDERCertificateMemory(context, mngr.get());
482 if (!context->certificatePath.empty()) {
483 loadPEMCertificateFile(context, mngr.get());
486 return validateFile(context, mngr.get());
489 XmlSec::Result XmlSec::validateNoHash(XmlSecContext *context)
491 xmlSecErrorsSetCallback(LogDebugPrint);
494 return validate(context);
497 XmlSec::Result XmlSec::validatePartialHash(XmlSecContext *context)
499 xmlSecErrorsSetCallback(LogDebugPrint);
501 m_partialHash = true;
502 return validate(context);
505 XmlSec::Result XmlSec::setPartialHashList(const std::list<std::string>& targetUri)
507 xmlSecErrorsSetCallback(LogDebugPrint);
509 m_pList = (std::list<std::string>*)&targetUri;
512 } // namespace ValidationCore