From: Kidong Kim Date: Wed, 22 Aug 2012 02:40:48 +0000 (+0900) Subject: source code open X-Git-Tag: 2.0_alpha^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=HEAD;p=framework%2Fsecurity%2Fcert-svc.git source code open --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cbc2b1..9fc7098 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -PROJECT(certsvc C) +PROJECT(certsvc) + +SET(CMAKE_VERBOSE_MAKEFILE off) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(EXEC_PREFIX "\${prefix}") @@ -7,11 +9,12 @@ SET(LIBDIR "\${prefix}/lib") SET(INCLUDEDIR "\${prefix}/include") SET(VERSION_MAJOR 1) SET(VERSION "${VERSION_MAJOR}.0.0") +SET(TARGET_VCORE_LIB "cert-svc-vcore") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) INCLUDE(FindPkgConfig) -pkg_check_modules(pkgs REQUIRED openssl dlog) +pkg_check_modules(pkgs REQUIRED openssl dlog glib-2.0) FOREACH(flag ${pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") @@ -26,6 +29,10 @@ SET(debug "-DCERT_SVC_LOG") # for debug SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed") +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed") +SET(CMAKE_SKIP_RPATH "TRUE") +SET(CMAKE_CXX_FLAGS "-O2 -std=c++0x -g -Wall") ################################################################################################### # for libcert-svc.so @@ -39,7 +46,7 @@ SET(libcert-svc_CFLAGS " ${CFLAGS} -fvisibility=hidden -g -fPIC -I${CMAKE_CURREN SET(libcert-svc_CPPFLAGS " -DPIC ") ADD_LIBRARY(cert-svc SHARED ${libcert-svc_SOURCES}) -TARGET_LINK_LIBRARIES(cert-svc ${pkgs_LDFLAGS} -L${prefix}/lib -lpthread) +TARGET_LINK_LIBRARIES(cert-svc ${pkgs_LDFLAGS} ${pkgs_LIBRARIES} -L${prefix}/lib -lpthread) SET_TARGET_PROPERTIES(cert-svc PROPERTIES COMPILE_FLAGS "${libcert-svc_CFLAGS} ${libcert-svc_CPPFLAGS}") SET_TARGET_PROPERTIES(cert-svc PROPERTIES SOVERSION ${VERSION_MAJOR}) SET_TARGET_PROPERTIES(cert-svc PROPERTIES VERSION ${VERSION}) @@ -59,9 +66,58 @@ SET_TARGET_PROPERTIES(dpkg-pki-sig PROPERTIES COMPILE_FLAGS "${PackageSignVerify ################################################################################################### CONFIGURE_FILE(cert-svc.pc.in cert-svc.pc @ONLY) +CONFIGURE_FILE(cert-svc-vcore.pc.in cert-svc-vcore.pc @ONLY) + +INSTALL(TARGETS cert-svc DESTINATION /usr/lib COMPONENT RuntimeLibraries) +INSTALL(PROGRAMS ${CMAKE_BINARY_DIR}/dpkg-pki-sig DESTINATION /usr/bin) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/cert-svc.pc DESTINATION /usr/lib/pkgconfig) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/cert-svc-vcore.pc DESTINATION /usr/lib/pkgconfig) +INSTALL(FILES ${PROJECT_SOURCE_DIR}/targetinfo DESTINATION /opt/share/cert-svc/) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/cert-service.h DESTINATION /usr/include) + +# Now we must create empty directory for certificates. +# Without this directories rpm package will fail during build. +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/etc/empty + DESTINATION /usr/share/cert-svc/ca-certs/code-signing/native + FILES_MATCHING PATTERN THISPATTERNMUSTNOTMATCH +) +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/etc/empty + DESTINATION /usr/share/cert-svc/ca-certs/code-signing/wac + FILES_MATCHING PATTERN THISPATTERNMUSTNOTMATCH +) +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/etc/empty + DESTINATION /opt/share/cert-svc/certs/code-signing/wac + FILES_MATCHING PATTERN THISPATTERNMUSTNOTMATCH +) +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/etc/empty + DESTINATION /opt/share/cert-svc/certs/sim/operator + FILES_MATCHING PATTERN THISPATTERNMUSTNOTMATCH +) +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/etc/empty + DESTINATION /opt/share/cert-svc/certs/sim/thirdparty + FILES_MATCHING PATTERN THISPATTERNMUSTNOTMATCH +) +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/etc/empty + DESTINATION /opt/share/cert-svc/certs/ssl + FILES_MATCHING PATTERN THISPATTERNMUSTNOTMATCH +) +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/etc/empty + DESTINATION /opt/share/cert-svc/certs/user + FILES_MATCHING PATTERN THISPATTERNMUSTNOTMATCH +) +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/etc/empty + DESTINATION /opt/share/cert-svc/certs/trusteduser + FILES_MATCHING PATTERN THISPATTERNMUSTNOTMATCH +) +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/etc/empty + DESTINATION /opt/share/cert-svc/certs/mdm/security + FILES_MATCHING PATTERN THISPATTERNMUSTNOTMATCH +) +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/etc/empty + DESTINATION /opt/share/cert-svc/certs/mdm/security/cert + FILES_MATCHING PATTERN THISPATTERNMUSTNOTMATCH +) -INSTALL(TARGETS cert-svc DESTINATION lib COMPONENT RuntimeLibraries) -INSTALL(PROGRAMS ${CMAKE_BINARY_DIR}/dpkg-pki-sig DESTINATION bin) -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/cert-svc.pc DESTINATION lib/pkgconfig) -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/targetinfo DESTINATION /opt/share/cert-svc/) -INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/cert-service.h DESTINATION include) +ADD_SUBDIRECTORY(vcore) +ADD_SUBDIRECTORY(etc) +ADD_SUBDIRECTORY(tests) diff --git a/LICENSE b/LICENSE index 9f19478..a795f06 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved. +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. Apache License Version 2.0, January 2004 @@ -188,7 +188,7 @@ Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved. same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + Copyright (c) 2011 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. diff --git a/TC/scenario1/utc_SecurityFW_cert_svc_add_certificate_to_store_func.c b/TC/scenario1/utc_SecurityFW_cert_svc_add_certificate_to_store_func.c index 3422ecb..6c6474a 100755 --- a/TC/scenario1/utc_SecurityFW_cert_svc_add_certificate_to_store_func.c +++ b/TC/scenario1/utc_SecurityFW_cert_svc_add_certificate_to_store_func.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/TC/scenario1/utc_SecurityFW_cert_svc_check_ocsp_status_func.c b/TC/scenario1/utc_SecurityFW_cert_svc_check_ocsp_status_func.c index c560c71..20617c7 100755 --- a/TC/scenario1/utc_SecurityFW_cert_svc_check_ocsp_status_func.c +++ b/TC/scenario1/utc_SecurityFW_cert_svc_check_ocsp_status_func.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/TC/scenario1/utc_SecurityFW_cert_svc_delete_certificate_from_store_func.c b/TC/scenario1/utc_SecurityFW_cert_svc_delete_certificate_from_store_func.c index d343d11..859228d 100755 --- a/TC/scenario1/utc_SecurityFW_cert_svc_delete_certificate_from_store_func.c +++ b/TC/scenario1/utc_SecurityFW_cert_svc_delete_certificate_from_store_func.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/TC/scenario1/utc_SecurityFW_cert_svc_extract_certificate_data_func.c b/TC/scenario1/utc_SecurityFW_cert_svc_extract_certificate_data_func.c index 39b8edf..b58a23f 100755 --- a/TC/scenario1/utc_SecurityFW_cert_svc_extract_certificate_data_func.c +++ b/TC/scenario1/utc_SecurityFW_cert_svc_extract_certificate_data_func.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/TC/scenario1/utc_SecurityFW_cert_svc_load_PFX_file_to_context_func.c b/TC/scenario1/utc_SecurityFW_cert_svc_load_PFX_file_to_context_func.c index 6fc1cc8..ac27762 100755 --- a/TC/scenario1/utc_SecurityFW_cert_svc_load_PFX_file_to_context_func.c +++ b/TC/scenario1/utc_SecurityFW_cert_svc_load_PFX_file_to_context_func.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/TC/scenario1/utc_SecurityFW_cert_svc_load_buf_to_context_func.c b/TC/scenario1/utc_SecurityFW_cert_svc_load_buf_to_context_func.c index 8cd6860..ed053b3 100755 --- a/TC/scenario1/utc_SecurityFW_cert_svc_load_buf_to_context_func.c +++ b/TC/scenario1/utc_SecurityFW_cert_svc_load_buf_to_context_func.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/TC/scenario1/utc_SecurityFW_cert_svc_load_file_to_context_func.c b/TC/scenario1/utc_SecurityFW_cert_svc_load_file_to_context_func.c index c20a0df..ec49af7 100755 --- a/TC/scenario1/utc_SecurityFW_cert_svc_load_file_to_context_func.c +++ b/TC/scenario1/utc_SecurityFW_cert_svc_load_file_to_context_func.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/TC/scenario1/utc_SecurityFW_cert_svc_push_buf_into_context_func.c b/TC/scenario1/utc_SecurityFW_cert_svc_push_buf_into_context_func.c index 0ca3b9f..d797186 100755 --- a/TC/scenario1/utc_SecurityFW_cert_svc_push_buf_into_context_func.c +++ b/TC/scenario1/utc_SecurityFW_cert_svc_push_buf_into_context_func.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/TC/scenario1/utc_SecurityFW_cert_svc_push_file_into_context_func.c b/TC/scenario1/utc_SecurityFW_cert_svc_push_file_into_context_func.c index 41712d6..686cd3e 100755 --- a/TC/scenario1/utc_SecurityFW_cert_svc_push_file_into_context_func.c +++ b/TC/scenario1/utc_SecurityFW_cert_svc_push_file_into_context_func.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/TC/scenario1/utc_SecurityFW_cert_svc_search_certificate_func.c b/TC/scenario1/utc_SecurityFW_cert_svc_search_certificate_func.c index a21c31f..2cdcede 100755 --- a/TC/scenario1/utc_SecurityFW_cert_svc_search_certificate_func.c +++ b/TC/scenario1/utc_SecurityFW_cert_svc_search_certificate_func.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/TC/scenario1/utc_SecurityFW_cert_svc_verify_certificate_func.c b/TC/scenario1/utc_SecurityFW_cert_svc_verify_certificate_func.c index fbe1027..b58c578 100755 --- a/TC/scenario1/utc_SecurityFW_cert_svc_verify_certificate_func.c +++ b/TC/scenario1/utc_SecurityFW_cert_svc_verify_certificate_func.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/TC/scenario1/utc_SecurityFW_cert_svc_verify_signature_func.c b/TC/scenario1/utc_SecurityFW_cert_svc_verify_signature_func.c index 85ba9fa..1a91aa6 100755 --- a/TC/scenario1/utc_SecurityFW_cert_svc_verify_signature_func.c +++ b/TC/scenario1/utc_SecurityFW_cert_svc_verify_signature_func.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/build-stamp b/build-stamp new file mode 100644 index 0000000..e69de29 diff --git a/cert-svc-vcore.pc.in b/cert-svc-vcore.pc.in new file mode 100644 index 0000000..6df8a8d --- /dev/null +++ b/cert-svc-vcore.pc.in @@ -0,0 +1,12 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include/cert-svc + +Name: cert-svc-vcore +Description: cert-svc-vcore +Version: @VERSION@ +Requires: cert-svc libxml-2.0 libxslt openssl libsoup-2.4 dpl-efl secure-storage xmlsec1 +Libs: -lcert-svc-vcore -L${libdir} +Cflags: -I${includedir} + diff --git a/debian/changelog b/debian/changelog old mode 100644 new mode 100755 index 37d341c..f67849f --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,131 @@ +cert-svc (1.0.1-31) unstable; urgency=low + + * Add dependencies to xmlsec1 and libxml-2.0. + + * Git : framework/security/cert-svc + * Tag : cert-svc_1.0.1-31 + + -- Bartlomiej Grzelewski Thu, 17 Aug 2012 10:45:00 +0200 + +cert-svc (1.0.1-30) unstable; urgency=low + + * Remove UI from cert-svc repository. + + * Git : slp/pkgs/c/cert-svc + * Tag : cert-svc_1.0.1-30 + + -- Bartlomiej Grzelewski Thu, 16 Aug 2012 16:25:00 +0200 + +cert-svc (1.0.1-29) unstable; urgency=low + + * Fixed cert-svc-vcore pc file + + * Git : slp/pkgs/c/cert-svc + * Tag : cert-svc_1.0.1-29 + + -- Tomasz Swierczek Tue, 14 Aug 2012 10:12:00 +0200 + + +cert-svc (1.0.1-28) unstable; urgency=low + + * Remove "com.samsung" from source + * Add an "delete pkcs12/pfx" funcionality and screen to Cert UI + * Switch dependencies from ui-gadget to ui-gadget-1 + * Link ubuntu certificates into cert-svc store. + * Fix api. + + * Git : framework/security/cert-svc + * Tag : cert-svc_1.0.1-28 + + -- Tomasz Swierczek Mon, 13 Aug 2012 18:51:00 +0200 + +cert-svc (1.0.1-27) unstable; urgency=low + + * Selection screen added as separate EFL gadget + + * Git : slp/pkgs/c/cert-svc + * Tag : cert-svc_1.0.1-27 + + -- Tomasz Swierczek Tue, 31 Jul 2012 17:14:00 +0200 + +cert-svc (1.0.1-26) unstable; urgency=low + + * Selection screen runs correctly with another EFL app + * Added test for selection screen + * Corrected comments in cert-ui-api.h + + * Git : slp/pkgs/c/cert-svc + * Tag : cert-svc_1.0.1-26 + + -- Tomasz Swierczek Wed, 25 Jul 2012 18:39:00 +0200 + +cert-svc (1.0.1-25) unstable; urgency=low + + * another RPMization + * added selection screen + * added pkcs12 container install/browse menu + * added cert-svc-ui-api library + + * Git : slp/pkgs/c/cert-svc + * Tag : cert-svc_1.0.1-25 + + -- Tomasz Swierczek Tue, 24 Jul 2012 22:55:00 +0200 + +cert-svc (1.0.1-24) unstable; urgency=low + + * added selection screen + * added pkcs12 container install/browse menu + * added cert-svc-ui-api library + + * Git : slp/pkgs/c/cert-svc + * Tag : cert-svc_1.0.1-24 + + -- Tomasz Swierczek Tue, 24 Jul 2012 22:55:00 +0200 + +cert-svc (1.0.1-23) unstable; urgency=low + + * Redebianized. + * Remove deprecated dependency from tapi and pkgmgr. + + * Git : slp/pkgs/c/cert-svc + * Tag : cert-svc_1.0.1-23 + + -- Bartlomiej Grzelewski Mon, 18 Jul 2012 18:05:11 +0100 + +cert-svc (1.0.1-22) unstable; urgency=low + + * Redebianized. + * Remove deprecated function call from lib. + + * Git : slp/pkgs/c/cert-svc + * Tag : cert-svc_1.0.1-22 + + -- Bartlomiej Grzelewski Mon, 17 Jul 2012 18:15:00 +0100 + +cert-svc (1.0.1-19) unstable; urgency=low + + * Redebianized + + * Git : slp/pkgs/c/cert-svc + * Tag : cert-svc_1.0.1-19 + + -- Tomasz Swierczek Mon, 04 Jun 2012 17:41:00 +0100 + +cert-svc (1.0.1-18) unstable; urgency=low + + * Move VCore to cert-svc repository + * Add test for vcore c-api. + * Added Cert UI Package + + * Git : slp/pkgs/c/cert-svc + * Tag : cert-svc_1.0.1-18 + + -- Tomasz Swierczek Mon, 04 Jun 2012 17:20:00 +0100 + cert-svc (1.0.1-17) unstable; urgency=low - * add certificate store for MDM - * Git: pkgs/c/cert-svc + * add certificate store for MDM + * Git: slp/pkgs/c/cert-svc * Tag: cert-svc_1.0.1-17 -- Kidong Kim Thu, 02 Feb 2012 09:29:17 +0900 @@ -10,7 +134,7 @@ cert-svc (1.0.1-16) unstable; urgency=low * 11/12/21 * - remove self-signed certificate from certificate chain - * Git: pkgs/c/cert-svc + * Git: slp/pkgs/c/cert-svc * Tag: cert-svc_1.0.1-16 -- Kidong Kim Wed, 21 Dec 2011 10:06:41 +0900 @@ -19,7 +143,131 @@ cert-svc (1.0.1-15) unstable; urgency=low * 11/12/07 * - add boiler-plate on testcases - * Git: pkgs/c/cert-svc + * Git: 165.213.180.234:slp/pkgs/c/cert-svc * Tag: cert-svc_1.0.1-15 -- Kidong Kim Wed, 07 Dec 2011 09:47:17 +0900 + +cert-svc (1.0.1-14) unstable; urgency=low + + * 11/12/02 + * - change license : LGPL -> apache + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-14 + + -- Kidong Kim Fri, 02 Dec 2011 16:59:02 +0900 + +cert-svc (1.0.1-13) unstable; urgency=low + + * 11/11/30 + * - make all certificate stores and change ownership and permission of those + * - use dlog instead of console(fprintf) for logging + * - get length of private key when using PFX format certificate + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-13 + + -- Kidong Kim Wed, 30 Nov 2011 16:17:49 +0900 + +cert-svc (1.0.1-12) unstable; urgency=low + + * add testcases + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-12 + + -- Kidong Kim Fri, 14 Oct 2011 14:00:11 +0900 + +cert-svc (1.0.1-11) unstable; urgency=low + + * fix dependency problem + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-11 + + -- Kidong Kim Mon, 29 Aug 2011 09:39:01 +0900 + +cert-svc (1.0.1-10) unstable; urgency=low + + * remove dnet dependency + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-10 + + -- Kidong Kim Fri, 26 Aug 2011 10:18:08 +0900 + +cert-svc (1.0.1-9) unstable; urgency=low + + * fix name field parsing problem (temp) + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-9 + + -- Kidong Kim Mon, 25 Jul 2011 17:22:13 +0900 + +cert-svc (1.0.1-8) unstable; urgency=low + + * fix search problem + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-8 + + -- Kidong Kim Thu, 14 Jul 2011 10:04:11 +0900 + +cert-svc (1.0.1-7) unstable; urgency=low + + * fix install bug + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-7 + + -- Kidong Kim Wed, 13 Jul 2011 12:27:53 +0900 + +cert-svc (1.0.1-6) unstable; urgency=low + + * fix boiler-plate + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-6 + + -- Kidong Kim Wed, 13 Jul 2011 10:12:13 +0900 + +cert-svc (1.0.1-5) unstable; urgency=low + + * fix bug - verify certificate, postinst + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-5 + + -- Kidong Kim Thu, 23 Jun 2011 15:27:48 +0900 + +cert-svc (1.0.1-4) unstable; urgency=low + + * fix bug - cannot calculate message length if message is not character string + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-4 + + -- Kidong Kim Sat, 18 Jun 2011 12:56:47 +0900 + +cert-svc (1.0.1-3) unstable; urgency=low + + * fix full-build error + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-3 + + -- Kidong Kim Tue, 14 Jun 2011 10:15:33 +0900 + +cert-svc (1.0.1-2) unstable; urgency=low + + * fix installation bug + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-2 + + -- Kidong Kim Sat, 11 Jun 2011 10:36:30 +0900 + +cert-svc (1.0.1-1) unstable; urgency=low + + * add dpkg-pki-sig, fix some bugs + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.1-1 + + -- Kidong Kim Fri, 10 Jun 2011 11:38:26 +0900 + +cert-svc (1.0.0-1) unstable; urgency=low + + * Initial Release + * Git: 165.213.180.234:slp/pkgs/c/cert-svc + * Tag: cert-svc_1.0.0-1 + + -- Kidong Kim Tue, 07 Jun 2011 13:48:44 +0900 diff --git a/debian/changelog.app b/debian/changelog.app new file mode 100755 index 0000000..bc77315 --- /dev/null +++ b/debian/changelog.app @@ -0,0 +1,6 @@ +mgr-app (0.0.1-1) unstable; urgency=low + + * first source package for building + + -- ManHyun Hwang Thu, 30 JUN 2011 13:43:34 +0900 + diff --git a/debian/changelog.ug b/debian/changelog.ug new file mode 100755 index 0000000..a6205af --- /dev/null +++ b/debian/changelog.ug @@ -0,0 +1,6 @@ +libug-setting-manage-application-efl (0.0.1-1) unstable; urgency=low + + * first source package for building + + -- ManHyun Hwang Thu, 30 JUN 2011 13:43:34 +0900 + diff --git a/debian/com.samsung.mgr-app-0.install.in b/debian/com.samsung.mgr-app-0.install.in new file mode 100755 index 0000000..e69de29 diff --git a/debian/com.samsung.mgr-app-dbg.install.in b/debian/com.samsung.mgr-app-dbg.install.in new file mode 100755 index 0000000..8b13789 --- /dev/null +++ b/debian/com.samsung.mgr-app-dbg.install.in @@ -0,0 +1 @@ + diff --git a/debian/com.samsung.mgr-app.desktop.in b/debian/com.samsung.mgr-app.desktop.in new file mode 100755 index 0000000..8be86fa --- /dev/null +++ b/debian/com.samsung.mgr-app.desktop.in @@ -0,0 +1,24 @@ +Name=manage application +Exec=${PREFIX}/bin/mgr-app +Hidden=False +Version=@VERSION@ +Type=Application +X-TIZEN-TaskManage=True +X-TIZEN-Multiple=False + +Name[en_US]=manage application +Name[nl_NL]=manage application +Name[de_DE]=manage application +Name[zh_HK]=manage application +Name[zh_CN]=manage application +Name[ru_RU]=manage application +Name[ko_KR]=manage application +Name[zh_TW]=manage application +Name[ja_JP]=manage application +Name[es_ES]=manage application +Name[el_GR]=manage application +Name[it_IT]=manage application +Name[tr_TR]=manage application +Name[pt_PT]=manage application +Name[fr_FR]=manage application + diff --git a/debian/com.samsung.mgr-app.postinst.in b/debian/com.samsung.mgr-app.postinst.in new file mode 100755 index 0000000..8c57239 --- /dev/null +++ b/debian/com.samsung.mgr-app.postinst.in @@ -0,0 +1,10 @@ +#!/bin/sh + +# file owner +if [ ${USER} == "root" ] +then + echo "Test if" +else + eche "Test else" +fi + diff --git a/debian/control b/debian/control old mode 100644 new mode 100755 index 7b97d80..a4d4ac5 --- a/debian/control +++ b/debian/control @@ -2,25 +2,70 @@ Source: cert-svc Section: libs Priority: extra Maintainer: KiDong Kim -Uploaders: -Build-Depends: libssl-dev, dlog-dev, ca-certificates -Standards-Version: 1.0.0 -Homepage: N/A +Build-Depends: debhelper (>= 5), + libappcore-efl-dev, + autotools-dev, + libelm-dev, + libslp-setting-dev, + libui-gadget-dev, + libbundle-dev, + libaul-1-dev, + libefreet-dev, + libeina-dev, + shared-mime-info, +# java-runtime-dev, + libail-0-dev, + libpkgmgr-client-dev, + libjava-parser-dev, + debhelper (>= 7.0.50), + libssl-dev, + dlog-dev, + ca-certificates, + wrt-commons-dev, + libxmlsec1-dev, + libsoup2.4-dev, + libecore-dev, + libxml2-dev, + libpcre-dev, + libslp-tapi-dev, + libappsvc-dev -Package: libcert-svc-dev +Package: libcert-svc1-ui Section: libs Architecture: any -Depends: ${misc:Depends}, libcert-svc-0 (= ${Source-Version}), libssl-dev, dlog-dev +Depends: ${shlibs:Depends}, ${misc:Depends}, libappsvc-dev +Description: Manage Application package + +#Package: libug-setting-manage-application-efl-dbg +#Section: debug +#Architecture: any +#Depends: ${shlibs:Depends}, ${misc:Depends}, libug-setting-manage-application-efl-0 (= ${binary:Version}) +#Description: Manage Application debug(unstripped) package + +Package: libcert-svc-dev +Section: libdevel +Architecture: any +Depends: ${misc:Depends}, libcert-svc1 (= ${binary:Version}), libssl-dev, dlog-dev Description: Certification service development package -Package: libcert-svc-0 +Package: libcert-svc1 Section: libs Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} +Provides: libcert-svc-0 +Replaces: libcert-svc-0 +Depends: ${shlibs:Depends}, ${misc:Depends}, sqlite3 Description: Certification service library and executable -Package: libcert-svc-dbg +Package: libcert-svc1-dbg Section: debug Architecture: any -Depends: ${misc:Depends}, libcert-svc-0 +Provides: libcert-svc-dbg +Replaces: libcert-svc-dbg +Depends: ${misc:Depends}, libcert-svc1 (= ${binary:Version}) Description: debug package of cert-svc library + +Package: libcert-svc1-test +Section: libs +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends}, libcert-svc1 (= ${binary:Version}) +Description: test program for cert-svc diff --git a/debian/control.app b/debian/control.app new file mode 100755 index 0000000..b70bc27 --- /dev/null +++ b/debian/control.app @@ -0,0 +1,31 @@ +Source: mgr-app +Section: libs +Priority: extra +Maintainer: SangJun Na , Manhyun Hwang , Eunmi Son +Build-Depends: debhelper (>= 5), + libappcore-efl-dev, + autotools-dev, + libelm-dev, + libslp-setting-dev, + libui-gadget-dev, + libbundle-dev, + libaul-1-dev, + libefreet-dev, + libeina-dev, + shared-mime-info, +# java-runtime-dev, + libail-0-dev, + libpkgmgr-client-dev, + libjava-parser-dev + +Package: mgr-app-0 +Section: libs +Architecture: armel +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Manage Application package + +Package: mgr-app-dbg +Section: debug +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, mgr-app-0 (= ${binary:Version}) +Description: Manage Application debug(unstripped) package diff --git a/debian/control.ug b/debian/control.ug new file mode 100755 index 0000000..2084fb5 --- /dev/null +++ b/debian/control.ug @@ -0,0 +1,31 @@ +Source: libug-setting-manage-application-efl +Section: libs +Priority: extra +Maintainer: SangJun Na , Manhyun Hwang , Eunmi Son +Build-Depends: debhelper (>= 5), + libappcore-efl-dev, + autotools-dev, + libelm-dev, + libslp-setting-dev, + libui-gadget-dev, + libbundle-dev, + libaul-1-dev, + libefreet-dev, + libeina-dev, + shared-mime-info, +# java-runtime-dev, + libail-0-dev, + libpkgmgr-client-dev, + libjava-parser-dev + +Package: libug-setting-manage-application-efl-0 +Section: libs +Architecture: armel +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Manage Application package + +Package: libug-setting-manage-application-efl-dbg +Section: debug +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, libug-setting-manage-application-efl-0 (= ${binary:Version}) +Description: Manage Application debug(unstripped) package diff --git a/debian/dirs b/debian/dirs deleted file mode 100644 index ca882bb..0000000 --- a/debian/dirs +++ /dev/null @@ -1,2 +0,0 @@ -usr/bin -usr/sbin diff --git a/debian/docs b/debian/docs deleted file mode 100644 index a0f0008..0000000 --- a/debian/docs +++ /dev/null @@ -1 +0,0 @@ -CMakeLists.txt diff --git a/debian/libcert-svc-0.install.in b/debian/libcert-svc-0.install.in deleted file mode 100644 index b0a52ae..0000000 --- a/debian/libcert-svc-0.install.in +++ /dev/null @@ -1,3 +0,0 @@ -@PREFIX@/lib/*.so* -@PREFIX@/bin/dpkg-pki-sig -/opt/share/cert-svc/targetinfo diff --git a/debian/libcert-svc-0.postinst b/debian/libcert-svc-0.postinst deleted file mode 100755 index eff9cfe..0000000 --- a/debian/libcert-svc-0.postinst +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -USE_CERT=6524 - -# make certificate store directory -mkdir -p /usr/share/cert-svc/ca-certs/code-signing/java/operator -mkdir -p /usr/share/cert-svc/ca-certs/code-signing/java/manufacture -mkdir -p /usr/share/cert-svc/ca-certs/code-signing/java/thirdparty -mkdir -p /usr/share/cert-svc/ca-certs/code-signing/debian -mkdir -p /usr/share/cert-svc/ca-certs/code-signing/wac - -mkdir -p /opt/share/cert-svc/certs/code-signing/java/operator -mkdir -p /opt/share/cert-svc/certs/code-signing/java/manufacture -mkdir -p /opt/share/cert-svc/certs/code-signing/java/thirdparty -mkdir -p /opt/share/cert-svc/certs/code-signing/wac -mkdir -p /opt/share/cert-svc/certs/sim/operator -mkdir -p /opt/share/cert-svc/certs/sim/thirdparty -mkdir -p /opt/share/cert-svc/certs/ssl -mkdir -p /opt/share/cert-svc/certs/user -mkdir -p /opt/share/cert-svc/certs/trusteduser -mkdir -p /opt/share/cert-svc/certs/mdm/security/cert - -if [ ${USER} == "root" ] -then - chown -R root:${USE_CERT} /opt/share/cert-svc/certs/ - chmod -R 0775 /opt/share/cert-svc/certs/ -fi - -if [ -e "/opt/etc/ssl/certs" ] -then - if [ ! -L "/usr/share/cert-svc/ca-certs/ssl" ] - then - ln -s /opt/etc/ssl/certs/ /usr/share/cert-svc/ca-certs/ssl - fi -fi diff --git a/debian/libcert-svc-dev.install b/debian/libcert-svc-dev.install new file mode 100644 index 0000000..a3d41f0 --- /dev/null +++ b/debian/libcert-svc-dev.install @@ -0,0 +1,3 @@ +/usr/include/* +/usr/lib/pkgconfig/* +/usr/lib/*.so diff --git a/debian/libcert-svc-dev.install.in b/debian/libcert-svc-dev.install.in deleted file mode 100644 index e2e41aa..0000000 --- a/debian/libcert-svc-dev.install.in +++ /dev/null @@ -1,2 +0,0 @@ -@PREFIX@/include/* -@PREFIX@/lib/pkgconfig/* diff --git a/debian/libcert-svc1-test.install b/debian/libcert-svc1-test.install new file mode 100644 index 0000000..f1becfa --- /dev/null +++ b/debian/libcert-svc1-test.install @@ -0,0 +1,6 @@ +/usr/bin/cert-svc-test* +/opt/apps/widget/tests/vcore_widget_uncompressed/* +/opt/apps/widget/tests/vcore_keys/* +/opt/apps/widget/tests/vcore_certs/* +/opt/apps/widget/tests/pkcs12/* +/opt/share/cert-svc/certs/code-signing/wac/root_cacert0.pem diff --git a/debian/libcert-svc1-ui.install b/debian/libcert-svc1-ui.install new file mode 100644 index 0000000..2b88b10 --- /dev/null +++ b/debian/libcert-svc1-ui.install @@ -0,0 +1,7 @@ +/opt/ug/lib/libmgr-cert-common.so +/opt/ug/lib/libmgr-cert-view.so +/opt/ug/lib/libug-setting-manage-certificates-efl.so.* +/opt/ug/lib/libug-setting-manage-certificates-efl.so +/opt/ug/res/edje/ug-setting-manage-certificates-efl/ +/opt/ug/res/images/ug-setting-manage-certificates-efl/ +/opt/ug/res/locale/*/*/ug-setting-manage-certificates-efl.mo diff --git a/debian/libcert-svc1.dirs b/debian/libcert-svc1.dirs new file mode 100644 index 0000000..6fd0611 --- /dev/null +++ b/debian/libcert-svc1.dirs @@ -0,0 +1,15 @@ +/usr/share/cert-svc/ca-certs/code-signing/java/operator +/usr/share/cert-svc/ca-certs/code-signing/java/manufacture +/usr/share/cert-svc/ca-certs/code-signing/java/thirdparty +/usr/share/cert-svc/ca-certs/code-signing/debian +/usr/share/cert-svc/ca-certs/code-signing/wac +/opt/share/cert-svc/certs/code-signing/java/operator +/opt/share/cert-svc/certs/code-signing/java/manufacture +/opt/share/cert-svc/certs/code-signing/java/thirdparty +/opt/share/cert-svc/certs/code-signing/wac +/opt/share/cert-svc/certs/sim/operator +/opt/share/cert-svc/certs/sim/thirdparty +/opt/share/cert-svc/certs/ssl +/opt/share/cert-svc/certs/user +/opt/share/cert-svc/certs/trusteduser +/opt/share/cert-svc/certs/mdm/security/cert diff --git a/debian/libcert-svc1.install b/debian/libcert-svc1.install new file mode 100644 index 0000000..73f8c2f --- /dev/null +++ b/debian/libcert-svc1.install @@ -0,0 +1,13 @@ +/usr/bin/cert_svc_create_clean_db.sh +/usr/lib/*.so.* +/usr/bin/dpkg-pki-sig +/opt/share/cert-svc/targetinfo +/usr/share/cert-svc/cert_svc_vcore_db.sql +/usr/share/cert-svc/fingerprint_list.xml +/usr/share/cert-svc/fingerprint_list.xsd +/usr/share/cert-svc/schema.xsd +/opt/share/cert-svc/certs/code-signing/wac/wac0.root.preproduction.pem +/opt/share/cert-svc/certs/code-signing/wac/wac0.root.production.pem +/opt/share/cert-svc/certs/code-signing/wac/wac0.publisherid.pem +/opt/share/cert-svc/certs/code-signing/wac/tizen0.root.preproduction.cert.pem + diff --git a/debian/libcert-svc1.links b/debian/libcert-svc1.links new file mode 100644 index 0000000..d422ef3 --- /dev/null +++ b/debian/libcert-svc1.links @@ -0,0 +1 @@ +/opt/etc/ssl/certs/ /usr/share/cert-svc/ca-certs/ssl diff --git a/debian/libcert-svc1.postinst b/debian/libcert-svc1.postinst new file mode 100755 index 0000000..fef53d3 --- /dev/null +++ b/debian/libcert-svc1.postinst @@ -0,0 +1,55 @@ +#!/bin/sh -e + +USE_CERT=6524 + +case "$1" in + configure) + if [ `whoami` = "root" ] + then + chown -R root:${USE_CERT} /opt/share/cert-svc/certs/ + chmod -R 0775 /opt/share/cert-svc/certs/ + fi + + if [ -z ${2} ] + then + echo "This is new install of wrt-security" + echo "Calling /usr/bin/cert_svc_create_clean_db.sh" + /usr/bin/cert_svc_create_clean_db.sh + else + # Find out old and new version of databases + VCORE_OLD_DB_VERSION=`sqlite3 /opt/dbspace/.cert_svc_vcore.db ".tables" | grep "DB_VERSION_"` + VCORE_NEW_DB_VERSION=`cat /usr/share/cert-svc/cert_svc_vcore_db.sql | tr '[:blank:]' '\n' | grep DB_VERSION_` + echo "OLD vcore database version ${VCORE_OLD_DB_VERSION}" + echo "NEW vcore database version ${VCORE_NEW_DB_VERSION}" + + if [ ${VCORE_OLD_DB_VERSION} -a ${VCORE_NEW_DB_VERSION} ] + then + if [ ${VCORE_OLD_DB_VERSION} = ${VCORE_NEW_DB_VERSION} ] + then + echo "Equal database detected so db installation ignored" + else + echo "Calling /usr/bin/cert_svc_create_clean_db.sh" + /usr/bin/cert_svc_create_clean_db.sh + fi + else + echo "Calling /usr/bin/cert_svc_create_clean_db.sh" + /usr/bin/cert_svc_create_clean_db.sh + fi + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/debian/rules b/debian/rules index b8bc22c..a9214ef 100755 --- a/debian/rules +++ b/debian/rules @@ -9,68 +9,75 @@ # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 +ppTYPE ?= ugapp + CFLAGS ?= -Wall -g -CXXFLAGS ?= -Wall -g -LDFLAGS ?= -PREFIX ?= /usr -DATADIR ?= /opt +LDFLAGS ?= +ifneq (,$(findstring app,$(TYPE))) + PKGNAME ?= mgr-app + PREFIX ?= /opt/apps/mgr-app + RESDIR ?= /opt/apps/mgr-app/res + DATADIR ?= /opt/apps/mgr-app/data +else + PKGNAME ?= libug-setting-manage-certificates-efl + PREFIX ?= /opt/ug + RESDIR ?= /opt/ug/res + DATADIR ?= /opt/ug/res/etc +endif ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) - CFLAGS += -O0 - CXXFLAGS += -O0 + CFLAGS += -O0 + BUILD_TYPE=Debug else - CFLAGS += -O2 - CXXFLAGS += -O2 + CFLAGS += -O2 + BUILD_TYPE=Release endif LDFLAGS += -Wl,--rpath=$(PREFIX)/lib -Wl,--as-needed +CMAKE_BUILD_DIR ?= $(CURDIR)/cmake_build_tmp +CMAKE_CERT_SVC_BUILD_DIR ?= $(CURDIR)/library + + configure: configure-stamp configure-stamp: dh_testdir # Add here commands to configure the package. - CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" LDFLAGS="$(LDFLAGS)" cmake . -DCMAKE_INSTALL_PREFIX=$(PREFIX) - - touch configure-stamp + cd $(CMAKE_CERT_SVC_BUILD_DIR) && cmake . + mkdir -p $(CMAKE_BUILD_DIR) && cd $(CMAKE_BUILD_DIR) && CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" cmake ../ui/ -DCMAKE_INSTALL_PREFIX="$(PREFIX)" -DCMAKE_BUILD_TYPE="$(BUILD_TYPE)" -DPKGNAME="$(PKGNAME)" -DTYPE="$(TYPE)" + touch $(CMAKE_BUILD_DIR)/configure-stamp + touch $(CMAKE_CERT_SVC_BUILD_DIR)/configure-stamp build: build-stamp - -build-stamp: configure-stamp +build-stamp: configure-stamp dh_testdir # Add here commands to compile the package. - $(MAKE) - #docbook-to-man debian/wavplayer.sgml > wavplayer.1 - - for f in `find $(CURDIR)/debian/ -name "*.in"`; do \ + cd $(CMAKE_CERT_SVC_BUILD_DIR) && $(MAKE) + cd $(CMAKE_BUILD_DIR) && $(MAKE) + + for f in `find $(CURDIR)/debian/ -name "$(PREFIX)*.in"`; do \ cat $$f > $${f%.in}; \ sed -i -e "s#@PREFIX@#$(PREFIX)#g" $${f%.in}; \ + sed -i -e "s#@RESDIR@#$(RESDIR)#g" $${f%.in}; \ sed -i -e "s#@DATADIR@#$(DATADIR)#g" $${f%.in}; \ + sed -i -e "s#@PKGNAME@#$(PKGNAME)#g" $${f%.in}; \ done - - touch $@ + touch $(CMAKE_BUILD_DIR)/$@ + touch $(CMAKE_CERT_SVC_BUILD_DIR)/$@ clean: dh_testdir dh_testroot rm -f build-stamp configure-stamp - # Add here commands to clean up after the build process. - -$(MAKE) clean - rm -rf CMakeCache.txt - rm -rf CMakeFiles - rm -rf cmake_install.cmake - rm -rf Makefile - rm -rf install_manifest.txt - rm -rf *.so - rm -rf *.pc - rm -rf *.service + # Add here commands to clean up after the build process. + rm -rf $(CMAKE_BUILD_DIR) for f in `find $(CURDIR)/debian/ -name "*.in"`; do \ rm -f $${f%.in}; \ done - dh_clean install: build @@ -79,8 +86,8 @@ install: build dh_clean -k dh_installdirs - # Add here commands to install the package into debian/wavplayer. - $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install + cd $(CMAKE_BUILD_DIR) && $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install + cd $(CMAKE_CERT_SVC_BUILD_DIR) && $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install # Build architecture-independent files here. @@ -91,26 +98,26 @@ binary-indep: build install binary-arch: build install dh_testdir dh_testroot - dh_installchangelogs - dh_installdocs - dh_installexamples + #dh_installchangelogs + #dh_installdocs + #dh_installexamples dh_install --sourcedir=debian/tmp -# dh_installmenu -# dh_installdebconf -# dh_installlogrotate -# dh_installemacsen -# dh_installpam -# dh_installmime -# dh_python -# dh_installinit -# dh_installcron -# dh_installinfo + #dh_installmenu + #dh_installdebconf + #dh_installlogrotate + #dh_installemacsen + #dh_installpam + #dh_installmime + #dh_python + #dh_installinit + #dh_installcron + #dh_installinfo dh_installman dh_link - dh_strip --dbg-package=libcert-svc-dbg + #dh_strip --dbg-package=$(PKGNAME)-dbg dh_compress dh_fixperms -# dh_perl + #dh_perl dh_makeshlibs dh_installdeb dh_shlibdeps @@ -120,3 +127,4 @@ binary-arch: build install binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure + diff --git a/etc/CMakeLists.txt b/etc/CMakeLists.txt new file mode 100644 index 0000000..9bb7c70 --- /dev/null +++ b/etc/CMakeLists.txt @@ -0,0 +1,31 @@ + +SET(ETC_DIR ${PROJECT_SOURCE_DIR}/etc) + + INSTALL(FILES + ${ETC_DIR}/cert_svc_create_clean_db.sh + DESTINATION /usr/bin + PERMISSIONS OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE + ) + +INSTALL(FILES + ${ETC_DIR}/schema.xsd + DESTINATION /usr/share/cert-svc/ + ) + +INSTALL(FILES + ${ETC_DIR}/fingerprint_list.xsd + DESTINATION /usr/share/cert-svc/ + ) + +INSTALL(FILES + ${ETC_DIR}/fingerprint_list.xml + DESTINATION /usr/share/cert-svc/ + ) + +ADD_SUBDIRECTORY(certificates) diff --git a/etc/cert_svc_create_clean_db.sh b/etc/cert_svc_create_clean_db.sh new file mode 100755 index 0000000..241e05e --- /dev/null +++ b/etc/cert_svc_create_clean_db.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# Copyright (c) 2011 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. +# +for name in cert_svc_vcore +do + rm -f /opt/dbspace/.$name.db + rm -f /opt/dbspace/.$name.db-journal + SQL="PRAGMA journal_mode = PERSIST;" + sqlite3 /opt/dbspace/.$name.db "$SQL" + SQL=".read /usr/share/cert-svc/"$name"_db.sql" + sqlite3 /opt/dbspace/.$name.db "$SQL" + touch /opt/dbspace/.$name.db-journal + chown root:6026 /opt/dbspace/.$name.db + chown root:6026 /opt/dbspace/.$name.db-journal + chmod 660 /opt/dbspace/.$name.db + chmod 660 /opt/dbspace/.$name.db-journal +done + + diff --git a/etc/certificates/CMakeLists.txt b/etc/certificates/CMakeLists.txt new file mode 100644 index 0000000..339c06b --- /dev/null +++ b/etc/certificates/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (c) 2011 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 CMakeLists.txt +# @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) +# @author Yunchan Cho (yunchan.cho@samsung.com) +# @version 1.0 +# @brief +# + +SET(CERT_DIR ${PROJECT_SOURCE_DIR}/etc/certificates) + +INSTALL(FILES + ${CERT_DIR}/wac0.root.preproduction.pem + ${CERT_DIR}/wac0.root.production.pem + ${CERT_DIR}/wac0.publisherid.pem + ${CERT_DIR}/tizen0.root.preproduction.cert.pem + DESTINATION /opt/share/cert-svc/certs/code-signing/wac/ + ) diff --git a/etc/certificates/tizen0.root.preproduction.cert.pem b/etc/certificates/tizen0.root.preproduction.cert.pem new file mode 100644 index 0000000..bbf523b --- /dev/null +++ b/etc/certificates/tizen0.root.preproduction.cert.pem @@ -0,0 +1,60 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + b3:cb:d1:5b:de:6e:66:95 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=KR, ST=Suwon, O=Samsung Electronics, OU=SLP, CN=SLP WebApp Temporary CA/emailAddress=yunchan.cho@samsung.com + Validity + Not Before: Dec 8 10:27:32 2011 GMT + Not After : Nov 30 10:27:32 2021 GMT + Subject: C=KR, ST=Suwon, O=Samsung Electronics, OU=SLP, CN=SLP WebApp Temporary CA/emailAddress=yunchan.cho@samsung.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:cb:46:b8:94:81:b1:83:d7:29:05:2a:33:01:9e: + 66:15:f8:be:bb:95:17:dd:7a:c4:c2:f5:d9:e4:aa: + fd:c8:8d:a9:48:65:fc:3d:dc:47:d7:2a:2f:5e:c7: + 1f:22:ed:e0:98:e6:43:6d:74:82:ca:7d:22:9c:60: + 44:18:cd:ca:d6:6b:16:ca:ed:63:c9:7a:f1:00:df: + e4:6b:33:47:2f:78:75:61:d7:c9:29:3e:a9:ee:76: + dd:2e:fe:9d:e7:3c:0d:02:f4:e9:2d:46:74:49:52: + ef:a0:d6:9d:4d:08:65:ea:6b:35:72:a5:08:d8:46: + 46:03:99:7c:66:8c:60:c4:91 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 47:A8:8F:CD:1F:22:BA:69:85:13:55:21:2D:C2:19:2D:5F:FF:DC:03 + X509v3 Authority Key Identifier: + keyid:47:A8:8F:CD:1F:22:BA:69:85:13:55:21:2D:C2:19:2D:5F:FF:DC:03 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + c2:c4:62:f2:ec:6f:2b:05:9c:09:cc:ae:e9:77:a9:1d:66:6b: + 03:7b:01:3a:e6:29:bb:2a:b8:15:d8:a1:7d:9b:05:b4:8c:cb: + ae:c7:eb:68:c0:e3:29:c7:e7:5a:ca:1a:0c:3a:ab:91:80:4f: + 9b:36:d4:45:b4:7b:2c:ef:f3:fd:cb:84:84:85:42:3d:ec:18: + 3f:5f:9e:b1:1f:8d:0a:57:89:51:e4:eb:7e:da:e9:79:82:61: + 38:ad:ca:94:43:71:00:73:13:b9:e9:ef:bc:68:c5:ff:5e:0a: + f6:b9:2a:3d:1d:21:77:22:d0:4e:e7:ad:da:31:0b:51:fa:44: + cd:fa +-----BEGIN CERTIFICATE----- +MIIC9jCCAl+gAwIBAgIJALPL0VvebmaVMA0GCSqGSIb3DQEBBQUAMIGTMQswCQYD +VQQGEwJLUjEOMAwGA1UECAwFU3V3b24xHDAaBgNVBAoME1NhbXN1bmcgRWxlY3Ry +b25pY3MxDDAKBgNVBAsMA1NMUDEgMB4GA1UEAwwXU0xQIFdlYkFwcCBUZW1wb3Jh +cnkgQ0ExJjAkBgkqhkiG9w0BCQEWF3l1bmNoYW4uY2hvQHNhbXN1bmcuY29tMB4X +DTExMTIwODEwMjczMloXDTIxMTEzMDEwMjczMlowgZMxCzAJBgNVBAYTAktSMQ4w +DAYDVQQIDAVTdXdvbjEcMBoGA1UECgwTU2Ftc3VuZyBFbGVjdHJvbmljczEMMAoG +A1UECwwDU0xQMSAwHgYDVQQDDBdTTFAgV2ViQXBwIFRlbXBvcmFyeSBDQTEmMCQG +CSqGSIb3DQEJARYXeXVuY2hhbi5jaG9Ac2Ftc3VuZy5jb20wgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBAMtGuJSBsYPXKQUqMwGeZhX4vruVF916xML12eSq/ciN +qUhl/D3cR9cqL17HHyLt4JjmQ210gsp9IpxgRBjNytZrFsrtY8l68QDf5GszRy94 +dWHXySk+qe523S7+nec8DQL06S1GdElS76DWnU0IZeprNXKlCNhGRgOZfGaMYMSR +AgMBAAGjUDBOMB0GA1UdDgQWBBRHqI/NHyK6aYUTVSEtwhktX//cAzAfBgNVHSME +GDAWgBRHqI/NHyK6aYUTVSEtwhktX//cAzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 +DQEBBQUAA4GBAMLEYvLsbysFnAnMrul3qR1mawN7ATrmKbsquBXYoX2bBbSMy67H +62jA4ynH51rKGgw6q5GAT5s21EW0eyzv8/3LhISFQj3sGD9fnrEfjQpXiVHk637a +6XmCYTitypRDcQBzE7np77xoxf9eCva5Kj0dIXci0E7nrdoxC1H6RM36 +-----END CERTIFICATE----- diff --git a/etc/certificates/wac0.publisherid.pem b/etc/certificates/wac0.publisherid.pem new file mode 100644 index 0000000..758fe66 --- /dev/null +++ b/etc/certificates/wac0.publisherid.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID9DCCAtygAwIBAgIOZscBAQACO65mNg72468wDQYJKoZIhvcNAQEFBQAwgZQx +CzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRlciBHbWJIMTEwLwYD +VQQLEyhQcmUtUHJvZHVjdGlvbiBUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMTQw +MgYDVQQDEytQcmUtUHJvZHVjdGlvbiBUQyBUcnVzdENlbnRlciBDbGFzcyAyIENB +IElJMB4XDTA2MDYwODE0MTYwMVoXDTI1MTIzMTIyNTk1OVowgZQxCzAJBgNVBAYT +AkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRlciBHbWJIMTEwLwYDVQQLEyhQcmUt +UHJvZHVjdGlvbiBUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMTQwMgYDVQQDEytQ +cmUtUHJvZHVjdGlvbiBUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBIElJMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3Ewnr8E24AqXnf1Lu7w/g79Hht+W +lvWQg7cPC7685oj0htT0SmDy94uQaC3qRzBJktLKCyuniABykhdTr04rGWgzqD8n +EzcFCt5k0gF39l3ND/JL+S2YJK/f/xc884hjcLsHUU7cAd6mDlVkOszFK86DNbu0 +noz0y1y462RIOvPCjkYl/GJ5zL62bdDbgFqrWMPZ54JFG0Rj1v575ygfOd2LwOXe +xjzqfYI4JOx9frKWakPTehW+0UY5UdF0cMvHuLJie9H0vOobR4vtkenbS283b6j7 +0WCoU/BeAr4qskvMs9WwkwDquO4XnzYQDsEVgjBu4H2W0ihNUYJbRo8wtQIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQU +DTX6+fYyziPR1HZxViaGOj66QOYwDQYJKoZIhvcNAQEFBQADggEBALZ0pfjOfePn +D/6QDCt+cjQ5+U4eKcOlJMXrpEAlnC6oAnN1hqbOQaj44aIAbNap36E/Hl9s0Uga +c4nz73o5uPvdDmbWzNnMz6ey5NU0XXNzHxQWFdb0+Z7Cho5txoZjjynYXmyQc3RJ +rrPI+6Uej6sEv15ZGirjABza6pNJ+2NLojLyUb+8et3OCLS+wJ4qrX/5uwgL50Lt +0M2iPdZv+gjZwNmNWYIflYrSXa3ujclH+EAkkk/G1JxPzhVI3cII3y2DUZQAPCcX +XQDXIX2zJo7bYaUYJhlEeiGX17cdXMXDT1tbXKKg2mRIga1K4lknn9U/vzkjMJXL +GA38dUZRZ2Y= +-----END CERTIFICATE----- diff --git a/etc/certificates/wac0.root.preproduction.pem b/etc/certificates/wac0.root.preproduction.pem new file mode 100644 index 0000000..7c46a6a --- /dev/null +++ b/etc/certificates/wac0.root.preproduction.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDijCCAnKgAwIBAgIOMwoBAQAuBBKsIqIni7QwDQYJKoZIhvcNAQELBQAwYDEL +MAkGA1UEBhMCR0IxJTAjBgNVBAoMHFdBQyBBcHBsaWNhdGlvbiBTZXJ2aWNlcyBM +dGQxKjAoBgNVBAMMIVdBQyBBcHBsaWNhdGlvbiBTZXJ2aWNlcyBMdGQgVEVTVDAe +Fw0xMTAzMDMxNTA3MTlaFw0zNjAzMDMxNTA3MTlaMGAxCzAJBgNVBAYTAkdCMSUw +IwYDVQQKDBxXQUMgQXBwbGljYXRpb24gU2VydmljZXMgTHRkMSowKAYDVQQDDCFX +QUMgQXBwbGljYXRpb24gU2VydmljZXMgTHRkIFRFU1QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQC1PB3UrpAQgLSVqHRPhHqdDJsjKQe/CT9oS4lA+mI/ +vkhAvam/EvcNrNHcLVvSph+Mj0d2Y2J9wkcNW7fS3qZJXtpMNU36r7XdBk9kiYhc +PwJbckCo9Pp8YFxkuR6xV6Cc4o54mO2mumxDQ1hbwCsc5CT7yQz0FVVhCE01X6JJ +D61DvqmAzCUpehmEXthNV/s/o8fL+I2mD75p8vNDyIZHSJX59czO3PriT3tH2h+0 +tQx7NEWG70fQEU2CzcH9UngPYU7xXqNOhT9GmI/yL3HTeYGNH3i5VHrBjxeTF11t +IWSUDWQX1W0Y7TbN06XcGcuqPgjZ9xMcV7S4OiCBJz5nAgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQp5dzy2tJEArpT +qcQWNXG6J7y5WTANBgkqhkiG9w0BAQsFAAOCAQEAoXuyi8AjMx2yKVpss7xpVi5v +aUjcHU3AlptjNCFrXI6Bw+KJGNo8ydYlEASRd5dL/pJ6/V+UuUt9EngjUSdYOZGB +OgCeB2sJI8EZSay2LLhOCmkAxltC94Y/KRzkKqsYvNc6yvF85d+d4gbokf4APjmR +1TSlZLZsVhwfR0k0mer2rHQGE5Ljezdk7ZGeEMLdn6WFScwjo980EI0OqEoJU3on ++1TTBYudZ4o3qMgHiFwJafUJ6i3zuYbi9x86zMqeI4dJTbsTKLM0QV8vIdzI9fkV +t1tO/uBBAsNFUv8PAYwP4AFyGvyJbR4uxwxuQZKrltgjSTkPGYR14JtrGk7Y9g== +-----END CERTIFICATE----- + diff --git a/etc/certificates/wac0.root.production.pem b/etc/certificates/wac0.root.production.pem new file mode 100644 index 0000000..efccefd --- /dev/null +++ b/etc/certificates/wac0.root.production.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDgTCCAmmgAwIBAgIPAKTxAAEALtiV8/+rhB6+MA0GCSqGSIb3DQEBCwUAMFsx +CzAJBgNVBAYTAkdCMSUwIwYDVQQKDBxXQUMgQXBwbGljYXRpb24gU2VydmljZXMg +THRkMSUwIwYDVQQDDBxXQUMgQXBwbGljYXRpb24gU2VydmljZXMgTHRkMB4XDTEx +MDMxNDE0MDEwNFoXDTM2MDMxNDE0MDEwNFowWzELMAkGA1UEBhMCR0IxJTAjBgNV +BAoMHFdBQyBBcHBsaWNhdGlvbiBTZXJ2aWNlcyBMdGQxJTAjBgNVBAMMHFdBQyBB +cHBsaWNhdGlvbiBTZXJ2aWNlcyBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDCf6RHUPVBUY4YXYMdrmt5yO95eRCOG6vJtI9w0UM2w/2fihD5SMYa +3cCVam4j6F8FSspMIx+4CTCwdDSUixBGENwGEhD4qxqqV3KTObmxmYbELa97S1IP +qwoFelzUX6e+qHmYHi+eu/hONeiZaPBLtUtCd6ppCd5ACrD/kf/Ug/tfUtngozjG +sJ1UB10Ezi3fKs3OkkZMuecJvjWmDpRAyvIeeV8xfzeyn+DMpvhnI9RrSY0j4huE +ud6Lzzg0jV8+m54v0j7hv9klyNcGiZ+bmHr0LIyAtT+uktcms/4p3V9j01SI9Tmw +HcHKDXnM6kuThWpr6DR9KFSZ8zD2Nx5nAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBT5bKdU2+CGE17R+o/rMCZHHMn+ +WzANBgkqhkiG9w0BAQsFAAOCAQEAXmO+J5suIGuzbfYBoTdr8gahFfWEbhm1y6mJ +eZAc+Mf5L+In20p+Oj5uy6LsTmJsE9VE/+gi1eALKl9EhgYhET2ZlAzRFCN5dTWv +NTAFxJfGMkn2U5iW+luJ+lejyYBqEEFRpzwhXZbVDZQLim4CU75H75KzFkUgTulG +5M6U/Plt6S1rKgMkeYiR27W4C2NZMFXYqctt0m+eKEa3ueZE9pYUxqVcvQKSI017 +Nbc1kSkcuSKFV2Bk2T5dh5jQvywykdWLubAe6XiiC5CIT31kcSX6AlVhgNxWRRKP +QFO7lWqxnQMR2Or38ve7oSg1oL5Sx80fcbp3ovaYSKt5jnVWfg== +-----END CERTIFICATE----- + diff --git a/etc/empty/.gitignore b/etc/empty/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/etc/fingerprint_list.xml b/etc/fingerprint_list.xml new file mode 100644 index 0000000..970c718 --- /dev/null +++ b/etc/fingerprint_list.xml @@ -0,0 +1,21 @@ + + + AF:90:29:D2:B2:E1:6F:D6:7E:7E:EC:8E:BE:74:FA:4C:00:9C:49:FE + A6:00:BC:53:AC:37:5B:6A:03:C3:7A:8A:E0:1B:87:8B:82:94:9B:C2 + C2:C4:B5:72:9A:CF:D9:72:C5:DE:C1:E1:30:FF:74:7F:7A:AF:27:12 + + + AF:90:29:D2:B2:E1:6F:D6:7E:7E:EC:8E:BE:74:FA:4C:00:9C:49:FE + C2:C4:B5:72:9A:CF:D9:72:C5:DE:C1:E1:30:FF:74:7F:7A:AF:27:12 + A0:59:D3:37:E8:C8:2E:7F:38:84:7D:21:A9:9E:19:A9:8E:EC:EB:E1 + 8D:1F:CB:31:68:11:DA:22:59:26:58:13:6C:C6:72:C9:F0:DE:84:2A + + + 4A:9D:7A:4B:3B:29:D4:69:0A:70:B3:80:EC:A9:44:6B:03:7C:9A:38 + + + + + AD:A1:44:89:6A:35:6D:17:01:E9:6F:46:C6:00:7B:78:BE:2E:D9:4E + + diff --git a/etc/fingerprint_list.xsd b/etc/fingerprint_list.xsd new file mode 100644 index 0000000..b0fab23 --- /dev/null +++ b/etc/fingerprint_list.xsd @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/etc/schema.xsd b/etc/schema.xsd new file mode 100644 index 0000000..8028f3e --- /dev/null +++ b/etc/schema.xsd @@ -0,0 +1,415 @@ + + + + + + ]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/include/cert-service-debug.h b/include/cert-service-debug.h index f37b04d..3755894 100644 --- a/include/cert-service-debug.h +++ b/include/cert-service-debug.h @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/include/cert-service-process.h b/include/cert-service-process.h index 2008655..d085f51 100644 --- a/include/cert-service-process.h +++ b/include/cert-service-process.h @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/include/cert-service-store.h b/include/cert-service-store.h index 27126dd..2d75670 100644 --- a/include/cert-service-store.h +++ b/include/cert-service-store.h @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/include/cert-service-util.h b/include/cert-service-util.h index 39f626e..3ca26d4 100644 --- a/include/cert-service-util.h +++ b/include/cert-service-util.h @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/include/cert-service.h b/include/cert-service.h index d567166..88485d8 100644 --- a/include/cert-service.h +++ b/include/cert-service.h @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * @@ -54,10 +54,12 @@ extern "C" { #define CERT_SVC_ERR_PERMISSION_DENIED -16 #define CERT_SVC_ERR_IS_EXPIRED -17 /* default certificate file path */ -#define CERT_SVC_STORE_PATH "/opt/share/cert-svc/certs/" -#define CERT_SVC_STORE_PATH_DEFAULT "/opt/share/cert-svc/certs/ssl/" -#define CERT_SVC_SEARCH_PATH_RO "/usr/share/cert-svc/ca-certs/" -#define CERT_SVC_SEARCH_PATH_RW "/opt/share/cert-svc/certs/" +#define CERT_SVC_STORE_PATH "/opt/share/cert-svc/certs/" +#define CERT_SVC_STORE_PATH_KEYS "/opt/share/cert-svc/keys/" +#define CERT_SVC_STORE_PATH_DEFAULT "//* opt/share/cert-svc/certs/ssl/ */" +#define CERT_SVC_SEARCH_PATH_RO "/usr/share/cert-svc/ca-certs/" +#define CERT_SVC_SEARCH_PATH_RW "/opt/share/cert-svc/certs/" +#define CERT_SVC_STORE_PATH_PKCS12 "/opt/share/cert-svc/pkcs12" /*********************************************************************************/ /* Type definitions */ diff --git a/packaging/cert-svc.spec b/packaging/cert-svc.spec index 10a91b0..e55143c 100644 --- a/packaging/cert-svc.spec +++ b/packaging/cert-svc.spec @@ -1,82 +1,143 @@ -Name: cert-svc -Summary: Certification service -Version: 1.0.1 -Release: 0 -Group: System/Libraries -License: Apache2.0 -Source0: cert-svc-%{version}.tar.gz +#sbs-git:slp/pkgs/c/cert-svc cert-svc 1.0.1 ad7eb7efcefb37b06017c69cb2fc44e6f7b6cab7 +Name: cert-svc +Summary: Certification service +Version: 1.0.1 +Release: 31 +Group: System/Libraries +License: SAMSUNG +Source0: %{name}-%{version}.tar.gz + +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig BuildRequires: cmake - BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(openssl) - +BuildRequires: pkgconfig(evas) +BuildRequires: pkgconfig(dpl-efl) +BuildRequires: pkgconfig(libsoup-2.4) +BuildRequires: pkgconfig(libpcre) +BuildRequires: pkgconfig(libpcrecpp) +BuildRequires: pkgconfig(xmlsec1) +BuildRequires: pkgconfig(secure-storage) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(libxml-2.0) +BuildRequires: pkgconfig(libxslt) + +Provides: libcert-svc-vcore.so.1 %description -Certification service +Certification service %package devel -Summary: Download agent +Summary: Certification service (development files) Group: Development/Libraries Requires: %{name} = %{version}-%{release} %description devel -Certification service (developement files) +Certification service (developement files) + +%package test +Summary: Certification service (tests) +Group: System/Misc +Requires: %{name} = %{version}-%{release} + +%description test +Certification service (tests) %prep %setup -q - %build cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} - - make %{?jobs:-j%jobs} %install rm -rf %{buildroot} %make_install +%clean +rm -rf %{buildroot} %post -mkdir -p /usr/share/cert-svc/ca-certs/code-signing/java/operator -mkdir -p /usr/share/cert-svc/ca-certs/code-signing/java/manufacture -mkdir -p /usr/share/cert-svc/ca-certs/code-signing/java/thirdparty -mkdir -p /usr/share/cert-svc/ca-certs/code-signing/debian -mkdir -p /usr/share/cert-svc/ca-certs/code-signing/wac - -mkdir -p /opt/share/cert-svc/certs/code-signing/java/operator -mkdir -p /opt/share/cert-svc/certs/code-signing/java/manufacture -mkdir -p /opt/share/cert-svc/certs/code-signing/java/thirdparty -mkdir -p /opt/share/cert-svc/certs/code-signing/wac -mkdir -p /opt/share/cert-svc/certs/sim/operator -mkdir -p /opt/share/cert-svc/certs/sim/thirdparty -mkdir -p /opt/share/cert-svc/certs/ssl -mkdir -p /opt/share/cert-svc/certs/user -mkdir -p /opt/share/cert-svc/certs/trusteduser -mkdir -p /opt/share/cert-svc/certs/mdm/security/cert - -chown -R :6524 /opt/share/cert-svc/certs/ -chmod -R 0775 /opt/share/cert-svc/certs/ - -ln -s /opt/etc/ssl/certs/ /usr/share/cert-svc/ca-certs/ssl - +/sbin/ldconfig +if [ -z ${2} ]; then + echo "This is new install of wrt-security" + echo "Calling /usr/bin/cert_svc_create_clean_db.sh" + /usr/bin/cert_svc_create_clean_db.sh +else + # Find out old and new version of databases + VCORE_OLD_DB_VERSION=`sqlite3 /opt/dbspace/.cert_svc_vcore.db ".tables" | grep "DB_VERSION_"` + VCORE_NEW_DB_VERSION=`cat /usr/share/cert-svc/cert_svc_vcore_db.sql | tr '[:blank:]' '\n' | grep DB_VERSION_` + echo "OLD vcore database version ${VCORE_OLD_DB_VERSION}" + echo "NEW vcore database version ${VCORE_NEW_DB_VERSION}" + + if [ ${VCORE_OLD_DB_VERSION} -a ${VCORE_NEW_DB_VERSION} ]; then + if [ ${VCORE_OLD_DB_VERSION} = ${VCORE_NEW_DB_VERSION} ]; then + echo "Equal database detected so db installation ignored" + else + echo "Calling /usr/bin/cert_svc_create_clean_db.sh" + /usr/bin/cert_svc_create_clean_db.sh + fi + else + echo "Calling /usr/bin/cert_svc_create_clean_db.sh" + /usr/bin/cert_svc_create_clean_db.sh + fi +fi + +ln -s /opt/etc/ssl/certs /usr/share/cert-svc/ca-certs/ssl %postun - +/sbin/ldconfig +rm /usr/share/cert-svc/ca-certs/ssl %files %defattr(-,root,root,-) -/usr/bin/dpkg-pki-sig +%{_bindir}/cert_svc_create_clean_db.sh +%{_libdir}/*.so.* +%{_bindir}/dpkg-pki-sig /opt/share/cert-svc/targetinfo -/usr/lib/libcert-svc.so.1 -/usr/lib/libcert-svc.so.1.0.0 +%{_datadir}/cert-svc/cert_svc_vcore_db.sql +%{_datadir}/cert-svc/fingerprint_list.xml +%{_datadir}/cert-svc/fingerprint_list.xsd +%{_datadir}/cert-svc/schema.xsd +%dir %attr(0755,root,use_cert) /usr/share/cert-svc +%dir %attr(0755,root,use_cert) /usr/share/cert-svc/ca-certs +%dir %attr(0755,root,use_cert) /usr/share/cert-svc/ca-certs/code-signing +%dir %attr(0755,root,use_cert) /usr/share/cert-svc/ca-certs/code-signing/native +%dir %attr(0755,root,use_cert) /usr/share/cert-svc/ca-certs/code-signing/wac +%dir %attr(0777,root,use_cert) /opt/share/cert-svc +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/certs +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/certs/code-signing +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/certs/code-signing/wac +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/certs/sim +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/certs/sim/operator +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/certs/sim/thirdparty +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/certs/ssl +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/certs/user +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/certs/trusteduser +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/certs/mdm +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/certs/mdm/security +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/certs/mdm/security/cert +%dir %attr(0777,root,use_cert) /opt/share/cert-svc/pkcs12 +/opt/share/cert-svc/certs/code-signing/wac/wac0.root.preproduction.pem +/opt/share/cert-svc/certs/code-signing/wac/wac0.root.production.pem +/opt/share/cert-svc/certs/code-signing/wac/wac0.publisherid.pem +/opt/share/cert-svc/certs/code-signing/wac/tizen0.root.preproduction.cert.pem %files devel %defattr(-,root,root,-) -/usr/lib/pkgconfig/cert-svc.pc -/usr/lib/libcert-svc.so -/usr/include/cert-service.h - +%{_includedir}/* +%{_libdir}/pkgconfig/* +%{_libdir}/*.so +%files test +%defattr(-,root,root,-) +%{_bindir}/cert-svc-test* +/opt/apps/widget/tests/vcore_widget_uncompressed/* +/opt/apps/widget/tests/vcore_keys/* +/opt/apps/widget/tests/vcore_certs/* +/opt/apps/widget/tests/pkcs12/* +/opt/share/cert-svc/certs/code-signing/wac/root_cacert0.pem +/opt/share/cert-svc/pkcs12/* diff --git a/srcs/cert-service-process.c b/srcs/cert-service-process.c index 2d3f57b..5c78414 100644 --- a/srcs/cert-service-process.c +++ b/srcs/cert-service-process.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/srcs/cert-service-store.c b/srcs/cert-service-store.c index b315e80..b992534 100644 --- a/srcs/cert-service-store.c +++ b/srcs/cert-service-store.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/srcs/cert-service-util.c b/srcs/cert-service-util.c index b5d7d03..5b2a157 100644 --- a/srcs/cert-service-util.c +++ b/srcs/cert-service-util.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/srcs/cert-service.c b/srcs/cert-service.c index 6f5d0e7..720d7df 100644 --- a/srcs/cert-service.c +++ b/srcs/cert-service.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/srcs/dpkg-pki-sig.c b/srcs/dpkg-pki-sig.c index 27d1496..7b56937 100644 --- a/srcs/dpkg-pki-sig.c +++ b/srcs/dpkg-pki-sig.c @@ -1,7 +1,7 @@ /* * certification service * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Kidong Kim * diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..c3a3354 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (c) 2011 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. +# + +ADD_SUBDIRECTORY(capi) +ADD_SUBDIRECTORY(pkcs12) +ADD_SUBDIRECTORY(vcore) diff --git a/tests/capi/CMakeLists.txt b/tests/capi/CMakeLists.txt new file mode 100644 index 0000000..8a0d34f --- /dev/null +++ b/tests/capi/CMakeLists.txt @@ -0,0 +1,71 @@ +# Copyright (c) 2011 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 CMakeLists.txt +# @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +SET(TARGET_VCOREC_TEST "cert-svc-tests-capi") + +PKG_CHECK_MODULES(VCOREC_TEST_DEP + libsoup-2.4 + dpl-test-efl + dpl-db-efl + libpcrecpp + REQUIRED + ) + +SET(VCOREC_TESTS_SOURCES + ${PROJECT_SOURCE_DIR}/tests/capi/api_tests.cpp + ${PROJECT_SOURCE_DIR}/tests/capi/test_cases.cpp + ) + +INCLUDE_DIRECTORIES( + ${PROJECT_SOURCE_DIR}/vcore/src + ${PROJECT_SOURCE_DIR}/tests/capi + ${VCOREC_TEST_DEP_INCLUDE_DIRS} + ) + +ADD_EXECUTABLE(${TARGET_VCOREC_TEST} ${VCOREC_TESTS_SOURCES}) + +ADD_DEFINITIONS("-DDPL_LOGS_ENABLED") + +TARGET_LINK_LIBRARIES(${TARGET_VCOREC_TEST} + ${TARGET_VCORE_LIB} + ${VCOREC_TEST_DEP_LIBRARIES} + ) + +INSTALL(TARGETS ${TARGET_VCOREC_TEST} + DESTINATION /usr/bin + PERMISSIONS OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE + ) + +INSTALL(FILES + ${PROJECT_SOURCE_DIR}/tests/capi/data/cert_a.pem + ${PROJECT_SOURCE_DIR}/tests/capi/data/cert_b.pem + ${PROJECT_SOURCE_DIR}/tests/capi/data/pkey.pem + DESTINATION /opt/share/cert-svc/pkcs12/test1st + PERMISSIONS OWNER_READ + GROUP_READ + WORLD_READ + ) + diff --git a/tests/capi/api_tests.cpp b/tests/capi/api_tests.cpp new file mode 100644 index 0000000..6ad8fea --- /dev/null +++ b/tests/capi/api_tests.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011 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 main.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main + */ +#include + +#include + +//#include +//#include // includes headers with g_type_init + +CertSvcInstance vinstance; + +int main (int argc, char *argv[]) +{ +// g_type_init(); +// g_thread_init(NULL); + certsvc_instance_new(&vinstance); + int status = DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv); + certsvc_instance_free(vinstance); + return status; +} + diff --git a/tests/capi/api_tests.h b/tests/capi/api_tests.h new file mode 100644 index 0000000..28e5481 --- /dev/null +++ b/tests/capi/api_tests.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 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 api_tests.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main + */ + +#include +#include +#include +#include +#include +#include + +extern CertSvcInstance vinstance; diff --git a/tests/capi/crl_cache.h b/tests/capi/crl_cache.h new file mode 100644 index 0000000..c71dfd9 --- /dev/null +++ b/tests/capi/crl_cache.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011 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 crl_cache.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief Example implementation of memory cache for crl. + */ +#ifndef _CRL_MEMORY_CACHE_H_ +#define _CRL_MEMORY_CACHE_H_ + +#include +#include +#include + +#include +#include + +typedef std::vector BinaryBuffer; + +typedef struct CrlRecord_t { + BinaryBuffer buffer; + time_t nextUpdate; +} CrlRecord; + +typedef std::map MemoryCache; + +void memoryCacheWrite( + const char *distributionPoint, + const char *body, + int bodySize, + time_t nextUpdateTime, + void *userParam) +{ + MemoryCache *cache = static_cast(userParam); + + CrlRecord record; + record.buffer.resize(bodySize); + memcpy(&record.buffer[0], body, bodySize); + record.nextUpdate = nextUpdateTime; + + cache->insert(std::make_pair(std::string(distributionPoint),record)); +} + +int memoryCacheRead( + const char *distributorPoint, + char **body, + int *bodySize, + time_t *nextUpdateTime, + void *userParam) +{ + MemoryCache *cache = static_cast(userParam); + auto iter = cache->find(distributorPoint); + if (iter == cache->end()) { + return 0; + } + CrlRecord record = iter->second; + *bodySize = record.buffer.size(); + *body = new char[*bodySize]; + memcpy(*body, &record.buffer[0], *bodySize); + *nextUpdateTime = record.nextUpdate; + return 1; +} + +void memoryCacheFree( + char *buffer, + void *) +{ + delete[] buffer; +} + +#endif // _CRL_MEMORY_CACHE_H_ + diff --git a/tests/capi/data/cert_a.pem b/tests/capi/data/cert_a.pem new file mode 100644 index 0000000..f062d94 --- /dev/null +++ b/tests/capi/data/cert_a.pem @@ -0,0 +1,64 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 85:7d:e1:c5:d9:de:7a:20 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=PL, ST=Mazowieckie, O=Samsung, OU=SPRC, CN=Operator Test Root Certificate/emailAddress=operator@samsung.com + Validity + Not Before: Jan 4 17:34:31 2011 GMT + Not After : Jan 4 17:34:31 2012 GMT + Subject: C=PL, ST=Malopolskie, L=Krakow, O=Samsung, OU=N/A, CN=Operator Test Second Level Certificate/emailAddress=second.operator@samsung.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:ba:3c:58:ca:87:1e:59:68:54:8a:54:34:43:61: + f1:81:e6:35:c1:46:74:16:c7:ff:f9:15:9e:0c:5a: + 6a:89:c1:13:0c:61:2e:ba:00:e0:71:ea:7e:31:ae: + 4e:ef:93:58:51:98:97:f3:bf:8a:9b:b2:c1:b7:0c: + 5f:3f:56:b3:13:3b:d0:80:be:04:66:89:84:50:ca: + fe:f6:f7:6b:05:3b:30:4e:96:9c:5b:c5:80:bc:d6: + be:6e:69:f4:b9:9b:4c:06:7a:ed:37:67:b2:fe:45: + 69:57:62:54:cb:69:69:48:b9:7d:a0:42:f1:b6:dc: + f2:7f:eb:75:2a:d4:83:69:b9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + D9:F3:11:BF:98:5A:60:12:7A:85:B5:E7:A7:38:4F:CF:51:1D:C6:B2 + X509v3 Authority Key Identifier: + keyid:25:A5:90:9F:4D:3A:A4:19:0A:80:46:5E:F3:FB:20:CE:56:30:33:DA + + Signature Algorithm: sha1WithRSAEncryption + 69:6c:26:81:51:91:a6:e6:11:dc:81:35:03:73:85:4f:2f:29: + 1f:20:f2:23:54:82:ca:8f:b8:a6:e3:3f:cd:72:5e:d7:e7:f5: + 84:8a:33:e2:51:9f:36:4b:30:85:f4:4f:87:c7:9a:69:0b:15: + 6e:92:c7:1f:2f:58:a4:57:f8:c2:cd:59:6c:d2:11:63:ae:bb: + b0:32:3f:09:e7:2e:ad:db:1b:fe:e7:a4:21:43:47:76:e1:de: + 36:bb:26:3f:16:76:20:ed:a4:68:c1:48:ae:2b:95:fb:f6:d2: + f2:7f:74:f6:83:e2:89:06:b5:89:54:6e:7f:cf:88:94:66:e8: + da:32 +-----BEGIN CERTIFICATE----- +MIIDPjCCAqegAwIBAgIJAIV94cXZ3nogMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYD +VQQGEwJQTDEUMBIGA1UECBMLTWF6b3dpZWNraWUxEDAOBgNVBAoTB1NhbXN1bmcx +DTALBgNVBAsTBFNQUkMxJzAlBgNVBAMTHk9wZXJhdG9yIFRlc3QgUm9vdCBDZXJ0 +aWZpY2F0ZTEjMCEGCSqGSIb3DQEJARYUb3BlcmF0b3JAc2Ftc3VuZy5jb20wHhcN +MTEwMTA0MTczNDMxWhcNMTIwMTA0MTczNDMxWjCBsTELMAkGA1UEBhMCUEwxFDAS +BgNVBAgTC01hbG9wb2xza2llMQ8wDQYDVQQHEwZLcmFrb3cxEDAOBgNVBAoTB1Nh +bXN1bmcxDDAKBgNVBAsTA04vQTEvMC0GA1UEAxMmT3BlcmF0b3IgVGVzdCBTZWNv +bmQgTGV2ZWwgQ2VydGlmaWNhdGUxKjAoBgkqhkiG9w0BCQEWG3NlY29uZC5vcGVy +YXRvckBzYW1zdW5nLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAujxY +yoceWWhUilQ0Q2HxgeY1wUZ0Fsf/+RWeDFpqicETDGEuugDgcep+Ma5O75NYUZiX +87+Km7LBtwxfP1azEzvQgL4EZomEUMr+9vdrBTswTpacW8WAvNa+bmn0uZtMBnrt +N2ey/kVpV2JUy2lpSLl9oELxttzyf+t1KtSDabkCAwEAAaN7MHkwCQYDVR0TBAIw +ADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUw +HQYDVR0OBBYEFNnzEb+YWmASeoW156c4T89RHcayMB8GA1UdIwQYMBaAFCWlkJ9N +OqQZCoBGXvP7IM5WMDPaMA0GCSqGSIb3DQEBBQUAA4GBAGlsJoFRkabmEdyBNQNz +hU8vKR8g8iNUgsqPuKbjP81yXtfn9YSKM+JRnzZLMIX0T4fHmmkLFW6Sxx8vWKRX ++MLNWWzSEWOuu7AyPwnnLq3bG/7npCFDR3bh3ja7Jj8WdiDtpGjBSK4rlfv20vJ/ +dPaD4okGtYlUbn/PiJRm6Noy +-----END CERTIFICATE----- diff --git a/tests/capi/data/cert_b.pem b/tests/capi/data/cert_b.pem new file mode 100644 index 0000000..343241f --- /dev/null +++ b/tests/capi/data/cert_b.pem @@ -0,0 +1,66 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 85:7d:e1:c5:d9:de:7a:1f + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=PL, ST=Mazowieckie, O=Samsung, OU=SPRC, CN=Operator Test Root Certificate/emailAddress=operator@samsung.com + Validity + Not Before: Jan 4 17:27:08 2011 GMT + Not After : Jan 3 17:27:08 2014 GMT + Subject: C=PL, ST=Mazowieckie, O=Samsung, OU=SPRC, CN=Operator Test Root Certificate/emailAddress=operator@samsung.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:c3:39:17:a8:f9:d0:69:37:9a:56:44:39:67:10: + 14:a9:4b:a2:0b:c7:fc:a1:e8:e8:f7:1c:06:f4:9c: + 83:f7:37:07:9d:9c:2c:1b:46:43:5f:f1:7b:91:a8: + cd:c0:76:00:d5:9c:c9:28:f7:91:28:b6:97:ec:85: + b1:10:0f:58:2e:f6:6f:98:b6:ab:7b:ca:08:10:7f: + 55:32:bf:32:db:a7:c2:86:83:03:ee:41:0a:24:de: + 17:e3:9d:8f:5b:fa:46:70:78:98:b4:c1:14:77:44: + ab:59:7c:4c:d3:4a:f7:54:f2:30:0d:38:73:95:9f: + 21:0e:a9:86:3e:fc:82:4e:0b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 25:A5:90:9F:4D:3A:A4:19:0A:80:46:5E:F3:FB:20:CE:56:30:33:DA + X509v3 Authority Key Identifier: + keyid:25:A5:90:9F:4D:3A:A4:19:0A:80:46:5E:F3:FB:20:CE:56:30:33:DA + DirName:/C=PL/ST=Mazowieckie/O=Samsung/OU=SPRC/CN=Operator Test Root Certificate/emailAddress=operator@samsung.com + serial:85:7D:E1:C5:D9:DE:7A:1F + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + b9:d7:72:49:09:d8:6f:61:94:51:40:9d:c3:d3:23:53:97:b8: + 12:ee:cb:dd:57:e6:1f:a2:76:38:5d:42:51:bd:a9:30:19:f7: + 67:5b:a8:67:4a:9e:a1:f0:a9:22:14:94:77:32:27:79:37:9c: + 0a:0f:52:80:14:62:00:94:45:85:3b:fd:ad:b4:c3:20:45:ba: + b7:91:1a:9e:38:51:0f:9b:d5:ce:74:c7:bd:4a:21:9a:2d:b5: + 71:0b:42:d2:95:72:66:fe:eb:11:ad:62:44:6c:32:4e:b4:00: + 37:d7:b8:d5:4b:f6:74:36:78:d6:ae:66:b3:ca:6e:42:ff:cb: + c2:e6 +-----BEGIN CERTIFICATE----- +MIIDnzCCAwigAwIBAgIJAIV94cXZ3nofMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYD +VQQGEwJQTDEUMBIGA1UECBMLTWF6b3dpZWNraWUxEDAOBgNVBAoTB1NhbXN1bmcx +DTALBgNVBAsTBFNQUkMxJzAlBgNVBAMTHk9wZXJhdG9yIFRlc3QgUm9vdCBDZXJ0 +aWZpY2F0ZTEjMCEGCSqGSIb3DQEJARYUb3BlcmF0b3JAc2Ftc3VuZy5jb20wHhcN +MTEwMTA0MTcyNzA4WhcNMTQwMTAzMTcyNzA4WjCBkjELMAkGA1UEBhMCUEwxFDAS +BgNVBAgTC01hem93aWVja2llMRAwDgYDVQQKEwdTYW1zdW5nMQ0wCwYDVQQLEwRT +UFJDMScwJQYDVQQDEx5PcGVyYXRvciBUZXN0IFJvb3QgQ2VydGlmaWNhdGUxIzAh +BgkqhkiG9w0BCQEWFG9wZXJhdG9yQHNhbXN1bmcuY29tMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDDOReo+dBpN5pWRDlnEBSpS6ILx/yh6Oj3HAb0nIP3Nwed +nCwbRkNf8XuRqM3AdgDVnMko95EotpfshbEQD1gu9m+Ytqt7yggQf1UyvzLbp8KG +gwPuQQok3hfjnY9b+kZweJi0wRR3RKtZfEzTSvdU8jANOHOVnyEOqYY+/IJOCwID +AQABo4H6MIH3MB0GA1UdDgQWBBQlpZCfTTqkGQqARl7z+yDOVjAz2jCBxwYDVR0j +BIG/MIG8gBQlpZCfTTqkGQqARl7z+yDOVjAz2qGBmKSBlTCBkjELMAkGA1UEBhMC +UEwxFDASBgNVBAgTC01hem93aWVja2llMRAwDgYDVQQKEwdTYW1zdW5nMQ0wCwYD +VQQLEwRTUFJDMScwJQYDVQQDEx5PcGVyYXRvciBUZXN0IFJvb3QgQ2VydGlmaWNh +dGUxIzAhBgkqhkiG9w0BCQEWFG9wZXJhdG9yQHNhbXN1bmcuY29tggkAhX3hxdne +eh8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQC513JJCdhvYZRRQJ3D +0yNTl7gS7svdV+YfonY4XUJRvakwGfdnW6hnSp6h8KkiFJR3Mid5N5wKD1KAFGIA +lEWFO/2ttMMgRbq3kRqeOFEPm9XOdMe9SiGaLbVxC0LSlXJm/usRrWJEbDJOtAA3 +17jVS/Z0NnjWrmazym5C/8vC5g== +-----END CERTIFICATE----- diff --git a/tests/capi/data/pkey.pem b/tests/capi/data/pkey.pem new file mode 100644 index 0000000..ab1214a --- /dev/null +++ b/tests/capi/data/pkey.pem @@ -0,0 +1,18 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,44C051D8935528BB + +iISuf9ELdyP5M0vlWOK4msH09HRAhN+43qRu/RDznpsTs2lX2sJITXXEmJC4EJzS +Zk4jf3ScTj1JsMGlg5k0mZWLmDb4kUxTRVUqJX2W4uUYEmWav7LQHRAsPwNUSMs3 +DzZabSf1vplnKKoL9mMtX4E0mj79AkJp7tARQu4Zn2FDMg/UnCErzhGeoFysztmM +v0Biyrf8yTbatMMr7Ea6rIsKS8KbkEeYDk4LpxBXkMeOutnnUUdhUEXZ/mwgJq2e ++8LLPiWdFsrGxPdub7iuLXidXSpOd9VaC9LN/ORKF+EiJtF+twWSBotxYOtwmtgj +xUHfXBcbaFoPnLKNS0nxwsOHF07LUfsCHzfVm1uGyWFkkLrPfcSjb6PahFlfO6w5 +fv8HnUOgeAjlhK6X+xhmw1tpwMUlmcYmq31eC8rwxP59jNQbhH6GVr5+rEMRHNgp +loC1WqthoRtBEC0bi99VpIHVIepe9G+p40sIropoUWftfDSLl3RtONg5GyyZWQ4a +ROxsiLHDZ7+q8eKkJuYPkiZ61/5MHuOsH5k57PG7ppG6/0p+ED4bTwxxDb6PU4pA +08xUTZQ0CUn1x80o/lKw+1E9TJOTbCvrEJAnMksfOkNkNyedgDJaxfV63wYvnL4+ +BLzCqa6djpe0Mg2olQieV/piRUt7JaGA7bnaMAn+bJ56PzUnMl0/WlxzGTMtHjkf +zUqgLLdxZpJP7zl4XleSfRWlPgL1iN1s84x48ej+MGgOGi7xTgX/sfCLkN4No/8k +c5Po+lQU261XAYNuAjtjUFQP/FgIMM9CnJrDWp8xHZXUJBo0c5lOKg== +-----END RSA PRIVATE KEY----- diff --git a/tests/capi/test_cases.cpp b/tests/capi/test_cases.cpp new file mode 100644 index 0000000..6b815ad --- /dev/null +++ b/tests/capi/test_cases.cpp @@ -0,0 +1,1114 @@ +/* + * Copyright (c) 2011 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. + */ +#include + +#include + +#include +#include + +#include + +#include "crl_cache.h" + +RUNNER_TEST(test01_certificate_new_from_file) +{ + CertSvcCertificate cert; + int result = certsvc_certificate_new_from_file( + vinstance, + "/opt/share/cert-svc/certs/code-signing/wac/wac.root.production.pem", + &cert); + RUNNER_ASSERT_MSG(CERTSVC_TRUE == result, "Error reading certificate"); + + CertSvcString string; + + certsvc_certificate_get_string_field( + cert, + CERTSVC_SUBJECT_COMMON_NAME, + &string); + + const char *ptr = "WAC Application Services Ltd"; + + const char *buffer; + int len; + + certsvc_string_to_cstring(string, &buffer, &len); + + result = strncmp( + buffer, + ptr, + strlen(ptr)); + + RUNNER_ASSERT_MSG(0 == result, "Error reading common name"); + + certsvc_certificate_free(cert); +} + +RUNNER_TEST(test02_certificate_search) +{ + CertSvcCertificateList handler; + int result = certsvc_certificate_search(vinstance, + CERTSVC_SUBJECT_COMMON_NAME, + "WAC Application Services Ltd", + &handler); + + RUNNER_ASSERT_MSG(1 == result, "Error in search method"); + + CertSvcCertificate cert; + + result = certsvc_certificate_list_get_one(handler, 0, &cert); + + RUNNER_ASSERT_MSG(CERTSVC_TRUE == result, "Error reading certificate"); + + CertSvcString string; + + certsvc_certificate_get_string_field( + cert, + CERTSVC_SUBJECT_COUNTRY_NAME, + &string); + + const char *ptr = "GB"; + const char *buffer; + + certsvc_string_to_cstring(string, &buffer, NULL); + + result = strncmp( + buffer, + ptr, + strlen(ptr)); + + RUNNER_ASSERT_MSG(0 == result, "Country does not match"); +} + +RUNNER_TEST(test03_is_signed_by) +{ + int result; + std::string googleCA = + "MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG" + "A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz" + "cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2" + "MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV" + "BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt" + "YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN" + "ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE" + "BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is" + "I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G" + "CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do" + "lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc" + "AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k"; + + std::string google2nd = + "MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV" + "UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi" + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw" + "MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh" + "d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD" + "QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx" + "PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g" + "5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo" + "3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG" + "A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX" + "BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov" + "L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG" + "AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF" + "BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB" + "BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc" + "q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR" + "bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv"; + + CertSvcCertificate cert1, cert2; + + result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)googleCA.c_str(), + googleCA.size(), + CERTSVC_FORM_DER_BASE64, + &cert1); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error reading certificate"); + + result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)google2nd.c_str(), + google2nd.size(), + CERTSVC_FORM_DER_BASE64, + &cert2); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error reading certificate"); + + int status; + result = certsvc_certificate_is_signed_by(cert2, cert1, &status); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Chain verification failed"); + RUNNER_ASSERT_MSG(CERTSVC_TRUE == status, "Chain verification failed"); +} + +RUNNER_TEST(test04_not_before_not_after) +{ + std::string google2nd = + "MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV" + "UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi" + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw" + "MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh" + "d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD" + "QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx" + "PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g" + "5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo" + "3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG" + "A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX" + "BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov" + "L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG" + "AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF" + "BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB" + "BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc" + "q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR" + "bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv"; + + CertSvcCertificate cert; + int result; + + result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char *)google2nd.c_str(), + google2nd.size(), + CERTSVC_FORM_DER_BASE64, + &cert); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error reading certificate"); + + time_t before, after; + result = certsvc_certificate_get_not_before(cert, &before); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error extracting NOT_BEFORE"); + RUNNER_ASSERT_MSG(before == 1084406400, "TODO"); + + result = certsvc_certificate_get_not_after(cert, &after); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error extracting NOT_AFTER"); + //extracted: date --date="May 12 23:59:59 2014 GMT" +%s + RUNNER_ASSERT_MSG(after == 1399939199, "TODO"); +} + +RUNNER_TEST(test05_get_clr_dist_points) +{ + std::string google2nd = + "MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV" + "UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi" + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw" + "MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh" + "d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD" + "QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx" + "PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g" + "5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo" + "3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG" + "A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX" + "BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov" + "L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG" + "AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF" + "BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB" + "BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc" + "q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR" + "bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv"; + + CertSvcCertificate cert; + + int result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)google2nd.c_str(), + google2nd.size(), + CERTSVC_FORM_DER_BASE64, + &cert); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate"); + + CertSvcStringList stringList; + + result = certsvc_certificate_get_crl_distribution_points(cert, &stringList); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading distribution points"); + + int size; + + result = certsvc_string_list_get_length(stringList, &size); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in string list"); + +// RUNNER_ASSERT_MSG(1 == size, "Distribution point list is too small"); + + CertSvcString vstring; + + result = certsvc_string_list_get_one(stringList, 0, &vstring); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in extracting result from list"); + + int len; + const char *ptr; + + certsvc_string_to_cstring(vstring, &ptr, &len); + + RUNNER_ASSERT_MSG(0 == strncmp(ptr,"http://crl.verisign.com/pca3.crl", len), "Check distribution points failed!"); +} + +RUNNER_TEST(test06_cert_get_field) +{ + std::string google2nd = + "MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV" + "UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi" + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw" + "MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh" + "d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD" + "QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx" + "PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g" + "5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo" + "3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG" + "A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX" + "BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov" + "L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG" + "AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF" + "BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB" + "BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc" + "q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR" + "bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv"; + + CertSvcCertificate cert; + + int result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)google2nd.c_str(), + google2nd.size(), + CERTSVC_FORM_DER_BASE64, + &cert); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + CertSvcString subject, issuer; + + result = certsvc_certificate_get_string_field( + cert, + CERTSVC_SUBJECT, + &subject); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading SUBJECT field."); + + result = certsvc_certificate_get_string_field( + cert, + CERTSVC_ISSUER, + &issuer); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading ISSUER field."); + + int size; + const char *ptr; + + certsvc_string_to_cstring(subject, &ptr, &size); + RUNNER_ASSERT_MSG(0 == strncmp(ptr, "/C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA", size), "Subject does not match."); + + certsvc_string_to_cstring(issuer, &ptr, &size); + RUNNER_ASSERT_MSG(0 == strncmp(ptr, "/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority", size), "Issuer does not match."); +} + +RUNNER_TEST(test07_chain_sort) +{ + std::string certEE = + "MIIDIjCCAougAwIBAgIQK59+5colpiUUIEeCdTqbuTANBgkqhkiG9w0BAQUFADBM" + "MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg" + "THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x" + "MzA5MzAyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh" + "MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRgw" + "FgYDVQQDFA9tYWlsLmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ" + "AoGBAK85FZho5JL+T0/xu/8NLrD+Jaq9aARnJ+psQ0ynbcvIj36B7ocmJRASVDOe" + "qj2bj46Ss0sB4/lKKcMP/ay300yXKT9pVc9wgwSvLgRudNYPFwn+niAkJOPHaJys" + "Eb2S5LIbCfICMrtVGy0WXzASI+JMSo3C2j/huL/3OrGGvvDFAgMBAAGjgecwgeQw" + "DAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLnRoYXd0" + "ZS5jb20vVGhhd3RlU0dDQ0EuY3JsMCgGA1UdJQQhMB8GCCsGAQUFBwMBBggrBgEF" + "BQcDAgYJYIZIAYb4QgQBMHIGCCsGAQUFBwEBBGYwZDAiBggrBgEFBQcwAYYWaHR0" + "cDovL29jc3AudGhhd3RlLmNvbTA+BggrBgEFBQcwAoYyaHR0cDovL3d3dy50aGF3" + "dGUuY29tL3JlcG9zaXRvcnkvVGhhd3RlX1NHQ19DQS5jcnQwDQYJKoZIhvcNAQEF" + "BQADgYEANYARzVI+hCn7wSjhIOUCj19xZVgdYnJXPOZeJWHTy60i+NiBpOf0rnzZ" + "wW2qkw1iB5/yZ0eZNDNPPQJ09IHWOAgh6OKh+gVBnJzJ+fPIo+4NpddQVF4vfXm3" + "fgp8tuIsqK7+lNfNFjBxBKqeecPStiSnJavwSI4vw6e7UN0Pz7A="; + + std::string certCA = + "MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV" + "UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi" + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw" + "MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh" + "d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD" + "QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx" + "PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g" + "5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo" + "3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG" + "A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX" + "BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov" + "L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG" + "AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF" + "BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB" + "BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc" + "q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR" + "bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv"; + + std::string certRCA = + "MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG" + "A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz" + "cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2" + "MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV" + "BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt" + "YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN" + "ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE" + "BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is" + "I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G" + "CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do" + "lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc" + "AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k"; + + CertSvcCertificate cert1, cert2, cert3; + + int result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)certEE.c_str(), + certEE.size(), + CERTSVC_FORM_DER_BASE64, + &cert1); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)certCA.c_str(), + certCA.size(), + CERTSVC_FORM_DER_BASE64, + &cert2); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)certRCA.c_str(), + certRCA.size(), + CERTSVC_FORM_DER_BASE64, + &cert3); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + CertSvcCertificate collection[3]; + collection[0] = cert1; + collection[1] = cert3; + collection[2] = cert2; + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == certsvc_certificate_chain_sort(collection, 3), "FAIL TO SORT CERTIFICATE"); + + RUNNER_ASSERT_MSG(collection[2].privateHandler == cert3.privateHandler, "certsvc_certificate_chain_sort failed"); + + collection[0] = cert1; + collection[1] = cert3; + + RUNNER_ASSERT_MSG(CERTSVC_FAIL == certsvc_certificate_chain_sort(collection, 2), "certsvc_certificate_chain_sort failed"); +} + +RUNNER_TEST(test08_message_verify_dsa_sha1) +{ + std::string magda = + "MIIEDzCCA3igAwIBAgIJAMdKgvadG/Z/MA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV" + "BAYTAlBMMQwwCgYDVQQIEwNNYXoxEDAOBgNVBAoTB1NhbXN1bmcxDTALBgNVBAsT" + "BFNQUkMxEDAOBgNVBAMTB1NhbXN1bmcxIjAgBgkqhkiG9w0BCQEWE3NhbXN1bmdA" + "c2Ftc3VuZy5jb20wHhcNMTExMDA1MTIxMTMzWhcNMjExMDAyMTIxMTMzWjCBijEL" + "MAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93aWVja2llMRIwEAYDVQQHEwlsZWdp" + "b25vd28xEDAOBgNVBAoTB3NhbXN1bmcxDTALBgNVBAsTBHNwcmMxDjAMBgNVBAMT" + "BW1hZ2RhMSAwHgYJKoZIhvcNAQkBFhFtYWdkYUBzYW1zdW5nLmNvbTCCAbcwggEr" + "BgcqhkjOOAQBMIIBHgKBgQC1PCOasFhlfMc1yjdcp7zkzXGiW+MpVuFlsdYwkAa9" + "sIvNrQLi2ulxcnNBeCHKDbk7U+J3/QwO2XanapQMUqvfjfjL1QQ5Vf7ENUWPNP7c" + "Evx82Nb5jWdHyRfV//TciBZN8GLNEbfhtWlhI6CbDW1AaY0nPZ879rSIk7/aNKZ3" + "FQIVALcr8uQAmnV+3DLIA5nTo0Bg0bjLAoGAJG7meUtQbMulRMdjzeCoya2FXdm+" + "4acvInE9/+MybXTB3bFANMyw6WTvk4K9RK8tm52N95cykTjpAbxqTMaXwkdWbOFd" + "VKAKnyxi/UKtY9Q6NmwJB2hbA1GUzhPko8rEda66CGl0VbyM1lKMJjA+wp9pG110" + "L0ov19Q9fvqKp5UDgYUAAoGBAKxAQg7MqCgkC0MJftYjNaKM5n1iZv4j1li49zKf" + "Y5nTLP+vYAvg0owLNYvJ5ncKfY1DACPU4/+tC7TTua95wgj5rwvAXnzgSyOGuSr0" + "fK9DyrH6E0LfXT+WuIQHahm2iSbxqPrChlnp5/EXDTBaO6Qfdpq0BP48ClZebxcA" + "+TYFo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVy" + "YXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUmSpShswvWtEABd+l3WxccRcCydUw" + "HwYDVR0jBBgwFoAUggh/2wAChuhTKqX6WK5nfxQ4yGAwDQYJKoZIhvcNAQEFBQAD" + "gYEAgfnAu/gMJRC/BFwkgvrHL0TV4ffPVAf7RSnZS6ib4IHGgrvXJvL+Qh7vHykv" + "ZIqD2L96nY2EaSNr0yXrT81YROndOQUJNx4Y/W8m6asu4hzANNZqWCbApPDIMK6V" + "cPA1wrKgZqbWp218WBqI2v9pXV0O+jpzxq1+GeQV2UsbRwc="; + + std::string message = "c2lnbmVkIGRhdGEK"; + std::string signature = "MC0CFQCL2pDA4S/zsHkDUCWOq7K6ebG14gIUHHoLsbeUd+BEqBXB6XjmcTncBRA="; + + CertSvcString msgb64, sigb64, msg, sig; + + int result = certsvc_string_new(vinstance, message.c_str(), message.size(), &msgb64); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading messsage."); + + result = certsvc_string_new(vinstance, signature.c_str(), signature.size(), &sigb64); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading signature."); + + CertSvcCertificate cert; + + result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)magda.c_str(), + magda.size(), + CERTSVC_FORM_DER_BASE64, + &cert); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + result = certsvc_base64_decode(msgb64, &msg); + RUNNER_ASSERT_MSG(result == CERTSVC_TRUE, "Error in decoding base64."); + result = certsvc_base64_decode(sigb64, &sig); + RUNNER_ASSERT_MSG(result == CERTSVC_TRUE, "Error in decoding base64."); + + int status; + result = certsvc_message_verify(cert, msg, sig, "sha1", &status); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in verify message."); + RUNNER_ASSERT_MSG(status == CERTSVC_TRUE, "Error in verify message."); +} + +RUNNER_TEST(test09_message_verify_rsa_sha1) +{ + std::string filip = + "MIIC4zCCAkygAwIBAgIJAMdKgvadG/Z+MA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV" + "BAYTAlBMMQwwCgYDVQQIEwNNYXoxEDAOBgNVBAoTB1NhbXN1bmcxDTALBgNVBAsT" + "BFNQUkMxEDAOBgNVBAMTB1NhbXN1bmcxIjAgBgkqhkiG9w0BCQEWE3NhbXN1bmdA" + "c2Ftc3VuZy5jb20wHhcNMTExMDA1MTIwMDUxWhcNMjExMDAyMTIwMDUxWjB4MQsw" + "CQYDVQQGEwJQTDEMMAoGA1UECBMDTUFaMQwwCgYDVQQHEwNMZWcxDDAKBgNVBAoT" + "A1NhbTENMAsGA1UECxMEU1BSQzEOMAwGA1UEAxMFRmlsaXAxIDAeBgkqhkiG9w0B" + "CQEWEWZpbGlwQHNhbXN1bmcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB" + "gQDS/sS0wXSCb34ojN8bWFd4Pl9eTLHh18UNGsPpLpp4itdfuc/OgyqaSoDwBzVh" + "EWAVLCTxexUa4Ncva+41NbkW4RCsFzeGs0ktpu1+8Q+v0QEOGqVF2rQkgilzDF/o" + "O56Fxw9vG1OA+qdQd3yOAV2EqLNBPrEYB9K5GFyffrakSQIDAQABo3sweTAJBgNV" + "HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp" + "Y2F0ZTAdBgNVHQ4EFgQUeyy3iV75KtOkpPFd6mnR9dFGZMwwHwYDVR0jBBgwFoAU" + "ggh/2wAChuhTKqX6WK5nfxQ4yGAwDQYJKoZIhvcNAQEFBQADgYEADtv0CBrQ1QCM" + "H9jKFjpSpq7zFKMXQeVtb/Zie823//woicg8kxnP5sS4dJWNXNb1iMLdhgV80g1y" + "t3gTWPxTtFzprQyNiJHTmrbNWXLX1roRVGUE/I8Q4xexqpbNlJIW2Jjm/kqoKfnK" + "xORG6HNPXZV29NY2fDRPPOIYoFQzrXI="; + + std::string message = "Q3plZ28gdHUgc3p1a2Fzej8K"; + std::string signature = + "xEIpVjEIUoDkYGtX2ih6Gbya0/gr7OMdvbBKmjqzfNh9GHqwrgjglByeC5sspUzPBUF4Vmg/hZqL" + "gSsxXw9bKEa8c6mTQoNX51IC0ELPsoUMIJF1gGdFu0SzKptvU0+ksiiOM+70+s5t8s3z0G5PeA7O" + "99oq8UlrX7GDlxaoTU4="; + + CertSvcString msgb64, sigb64, msg, sig; + + int result = certsvc_string_new(vinstance, message.c_str(), message.size(), &msgb64); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading messsage."); + + result = certsvc_string_new(vinstance, signature.c_str(), signature.size(), &sigb64); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading signature."); + + CertSvcCertificate cert; + + result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)filip.c_str(), + filip.size(), + CERTSVC_FORM_DER_BASE64, + &cert); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + result = certsvc_base64_decode(msgb64, &msg); + RUNNER_ASSERT_MSG(result == CERTSVC_TRUE, "Error in decoding base64."); + + result = certsvc_base64_decode(sigb64, &sig); + RUNNER_ASSERT_MSG(result == CERTSVC_TRUE, "Error in decoding base64."); + + int status; + result = certsvc_message_verify(cert, msg, sig, "sha1", &status); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in verify message."); + RUNNER_ASSERT_MSG(status == CERTSVC_SUCCESS, "Error in verify message."); + + message[0] = 'q'; + + result = certsvc_string_new(vinstance, message.c_str(), message.size(), &msgb64); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading messsage."); + + result = certsvc_base64_decode(msgb64, &msg); + RUNNER_ASSERT_MSG(result == CERTSVC_TRUE, "Error in decoding base64."); + + result = certsvc_message_verify(cert, msg, sig, "sha1", &status); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in verify message."); + RUNNER_ASSERT_MSG(status == CERTSVC_INVALID_SIGNATURE, "Error in verify message."); +} + +RUNNER_TEST(test10_message_verify_rsa_sha256) +{ + std::string filip = + "MIIC4zCCAkygAwIBAgIJAMdKgvadG/Z+MA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV" + "BAYTAlBMMQwwCgYDVQQIEwNNYXoxEDAOBgNVBAoTB1NhbXN1bmcxDTALBgNVBAsT" + "BFNQUkMxEDAOBgNVBAMTB1NhbXN1bmcxIjAgBgkqhkiG9w0BCQEWE3NhbXN1bmdA" + "c2Ftc3VuZy5jb20wHhcNMTExMDA1MTIwMDUxWhcNMjExMDAyMTIwMDUxWjB4MQsw" + "CQYDVQQGEwJQTDEMMAoGA1UECBMDTUFaMQwwCgYDVQQHEwNMZWcxDDAKBgNVBAoT" + "A1NhbTENMAsGA1UECxMEU1BSQzEOMAwGA1UEAxMFRmlsaXAxIDAeBgkqhkiG9w0B" + "CQEWEWZpbGlwQHNhbXN1bmcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB" + "gQDS/sS0wXSCb34ojN8bWFd4Pl9eTLHh18UNGsPpLpp4itdfuc/OgyqaSoDwBzVh" + "EWAVLCTxexUa4Ncva+41NbkW4RCsFzeGs0ktpu1+8Q+v0QEOGqVF2rQkgilzDF/o" + "O56Fxw9vG1OA+qdQd3yOAV2EqLNBPrEYB9K5GFyffrakSQIDAQABo3sweTAJBgNV" + "HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp" + "Y2F0ZTAdBgNVHQ4EFgQUeyy3iV75KtOkpPFd6mnR9dFGZMwwHwYDVR0jBBgwFoAU" + "ggh/2wAChuhTKqX6WK5nfxQ4yGAwDQYJKoZIhvcNAQEFBQADgYEADtv0CBrQ1QCM" + "H9jKFjpSpq7zFKMXQeVtb/Zie823//woicg8kxnP5sS4dJWNXNb1iMLdhgV80g1y" + "t3gTWPxTtFzprQyNiJHTmrbNWXLX1roRVGUE/I8Q4xexqpbNlJIW2Jjm/kqoKfnK" + "xORG6HNPXZV29NY2fDRPPOIYoFQzrXI="; + + std::string message = "Q3plZ28gdHUgc3p1a2Fzej8K"; + std::string signature = + "a5nGT6wnbQ8MLwLkG965E4e1Rv983E+v3nolLvvjuAKnfgWYb+70Da+T9ggYDTjngq+EBgC30w1p" + "EScrwye8ELefvRxDWy1+tWR4QRW/Nd4oN2U/pvozoabDSpe9Cvt0ECEOWKDqIYYnoWFjOiXg9VwD" + "HVVkQXvsSYu6thX/Xsk="; + + CertSvcString msgb64, sigb64, msg, sig; + + int result = certsvc_string_new(vinstance, message.c_str(), message.size(), &msgb64); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading messsage."); + + result = certsvc_string_new(vinstance, signature.c_str(), signature.size(), &sigb64); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading signature."); + + CertSvcCertificate cert; + + result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)filip.c_str(), + filip.size(), + CERTSVC_FORM_DER_BASE64, + &cert); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + result = certsvc_base64_decode(msgb64, &msg); + RUNNER_ASSERT_MSG(result == CERTSVC_TRUE, "Error in decoding base64."); + + result = certsvc_base64_decode(sigb64, &sig); + RUNNER_ASSERT_MSG(result == CERTSVC_TRUE, "Error in decoding base64."); + + int status; + result = certsvc_message_verify(cert, msg, sig, "sha256", &status); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in verify message."); + RUNNER_ASSERT_MSG(status == CERTSVC_SUCCESS, "Error in verify message."); + + message[0] = 'q'; + + result = certsvc_string_new(vinstance, message.c_str(), message.size(), &msgb64); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading messsage."); + + result = certsvc_base64_decode(msgb64, &msg); + RUNNER_ASSERT_MSG(result == CERTSVC_TRUE, "Error in decoding base64."); + + result = certsvc_message_verify(cert, msg, sig, "sha256", &status); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in verify message."); + RUNNER_ASSERT_MSG(status == CERTSVC_INVALID_SIGNATURE, "Error in verify message."); +} + +RUNNER_TEST(test11_ocsp) +{ + std::string certEE = + "MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh" + "bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu" + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g" + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe" + "BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX" + "DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE" + "YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0" + "aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC" + "ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv" + "2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q" + "N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO" + "r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN" + "f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH" + "U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU" + "TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb" + "VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg" + "SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv" + "biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg" + "MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw" + "AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv" + "ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu" + "Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd" + "IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv" + "bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1" + "QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O" + "WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf" + "SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw=="; + + + std::string certCA = + "MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx" + "ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g" + "RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw" + "MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH" + "QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j" + "b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j" + "b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj" + "YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN" + "AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H" + "KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm" + "VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR" + "SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT" + "cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ" + "6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu" + "MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS" + "kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB" + "BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f" + "BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv" + "c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH" + "AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO" + "BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG" + "OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU" + "A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o" + "0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX" + "RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH" + "qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV" + "U+4="; + + std::string certRCA = + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0" + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz" + "BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y" + "aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG" + "9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy" + "NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y" + "azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs" + "YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw" + "Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl" + "cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY" + "dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9" + "WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS" + "v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v" + "UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu" + "IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC" + "W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd"; + + CertSvcCertificate cert1, cert2, cert3; + + int result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)certEE.c_str(), + certEE.size(), + CERTSVC_FORM_DER_BASE64, + &cert1); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)certCA.c_str(), + certCA.size(), + CERTSVC_FORM_DER_BASE64, + &cert2); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)certRCA.c_str(), + certRCA.size(), + CERTSVC_FORM_DER_BASE64, + &cert3); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + CertSvcCertificate collection[3]; + collection[0] = cert1; + collection[1] = cert2; + collection[2] = cert3; + + int status; + result = certsvc_ocsp_check(collection, 3, collection, 3, NULL, &status); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in ocsp check."); + + RUNNER_ASSERT_MSG(status & CERTSVC_OCSP_GOOD, "Error in ocsp."); +} + +RUNNER_TEST(test12_ocsp) +{ + std::string googleCA = + "MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG" + "A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz" + "cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2" + "MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV" + "BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt" + "YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN" + "ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE" + "BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is" + "I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G" + "CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do" + "lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc" + "AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k"; + + std::string google2nd = + "MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV" + "UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi" + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw" + "MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh" + "d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD" + "QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx" + "PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g" + "5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo" + "3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG" + "A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX" + "BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov" + "L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG" + "AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF" + "BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB" + "BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc" + "q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR" + "bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv"; + + std::string google3rd = + "MIIDIjCCAougAwIBAgIQK59+5colpiUUIEeCdTqbuTANBgkqhkiG9w0BAQUFADBM" + "MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg" + "THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x" + "MzA5MzAyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh" + "MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRgw" + "FgYDVQQDFA9tYWlsLmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ" + "AoGBAK85FZho5JL+T0/xu/8NLrD+Jaq9aARnJ+psQ0ynbcvIj36B7ocmJRASVDOe" + "qj2bj46Ss0sB4/lKKcMP/ay300yXKT9pVc9wgwSvLgRudNYPFwn+niAkJOPHaJys" + "Eb2S5LIbCfICMrtVGy0WXzASI+JMSo3C2j/huL/3OrGGvvDFAgMBAAGjgecwgeQw" + "DAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLnRoYXd0" + "ZS5jb20vVGhhd3RlU0dDQ0EuY3JsMCgGA1UdJQQhMB8GCCsGAQUFBwMBBggrBgEF" + "BQcDAgYJYIZIAYb4QgQBMHIGCCsGAQUFBwEBBGYwZDAiBggrBgEFBQcwAYYWaHR0" + "cDovL29jc3AudGhhd3RlLmNvbTA+BggrBgEFBQcwAoYyaHR0cDovL3d3dy50aGF3" + "dGUuY29tL3JlcG9zaXRvcnkvVGhhd3RlX1NHQ19DQS5jcnQwDQYJKoZIhvcNAQEF" + "BQADgYEANYARzVI+hCn7wSjhIOUCj19xZVgdYnJXPOZeJWHTy60i+NiBpOf0rnzZ" + "wW2qkw1iB5/yZ0eZNDNPPQJ09IHWOAgh6OKh+gVBnJzJ+fPIo+4NpddQVF4vfXm3" + "fgp8tuIsqK7+lNfNFjBxBKqeecPStiSnJavwSI4vw6e7UN0Pz7A="; + + CertSvcCertificate cert1, cert2, cert3; + + int result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)google3rd.c_str(), + google3rd.size(), + CERTSVC_FORM_DER_BASE64, + &cert1); + + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)google2nd.c_str(), + google2nd.size(), + CERTSVC_FORM_DER_BASE64, + &cert2); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + result = certsvc_certificate_new_from_memory( + vinstance, + (const unsigned char*)googleCA.c_str(), + googleCA.size(), + CERTSVC_FORM_DER_BASE64, + &cert3); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in reading certificate."); + + CertSvcCertificate collection[3]; + collection[0] = cert1; + collection[1] = cert2; + collection[2] = cert3; + + int status; + result = certsvc_ocsp_check(collection, 3, collection, 3, NULL, &status); + RUNNER_ASSERT_MSG(CERTSVC_SUCCESS == result, "Error in ocsp check."); + + RUNNER_ASSERT_MSG(status & CERTSVC_OCSP_GOOD, "Error in ocsp."); +} + +RUNNER_TEST(test13_crl) +{ + const int MAXC = 3; + std::string cert[MAXC]; + cert[0] = + "MIIDIjCCAougAwIBAgIQK59+5colpiUUIEeCdTqbuTANBgkqhkiG9w0BAQUFADBM" + "MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg" + "THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x" + "MzA5MzAyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh" + "MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRgw" + "FgYDVQQDFA9tYWlsLmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ" + "AoGBAK85FZho5JL+T0/xu/8NLrD+Jaq9aARnJ+psQ0ynbcvIj36B7ocmJRASVDOe" + "qj2bj46Ss0sB4/lKKcMP/ay300yXKT9pVc9wgwSvLgRudNYPFwn+niAkJOPHaJys" + "Eb2S5LIbCfICMrtVGy0WXzASI+JMSo3C2j/huL/3OrGGvvDFAgMBAAGjgecwgeQw" + "DAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLnRoYXd0" + "ZS5jb20vVGhhd3RlU0dDQ0EuY3JsMCgGA1UdJQQhMB8GCCsGAQUFBwMBBggrBgEF" + "BQcDAgYJYIZIAYb4QgQBMHIGCCsGAQUFBwEBBGYwZDAiBggrBgEFBQcwAYYWaHR0" + "cDovL29jc3AudGhhd3RlLmNvbTA+BggrBgEFBQcwAoYyaHR0cDovL3d3dy50aGF3" + "dGUuY29tL3JlcG9zaXRvcnkvVGhhd3RlX1NHQ19DQS5jcnQwDQYJKoZIhvcNAQEF" + "BQADgYEANYARzVI+hCn7wSjhIOUCj19xZVgdYnJXPOZeJWHTy60i+NiBpOf0rnzZ" + "wW2qkw1iB5/yZ0eZNDNPPQJ09IHWOAgh6OKh+gVBnJzJ+fPIo+4NpddQVF4vfXm3" + "fgp8tuIsqK7+lNfNFjBxBKqeecPStiSnJavwSI4vw6e7UN0Pz7A="; + + cert[1] = + "MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV" + "UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi" + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw" + "MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh" + "d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD" + "QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx" + "PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g" + "5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo" + "3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG" + "A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX" + "BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov" + "L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG" + "AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF" + "BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB" + "BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc" + "q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR" + "bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv"; + + cert[2] = + "MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG" + "A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz" + "cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2" + "MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV" + "BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt" + "YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN" + "ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE" + "BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is" + "I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G" + "CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do" + "lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc" + "AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k"; + + + CertSvcCertificate certificate[MAXC]; + + int result, status; + + for (int i=0; i +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDZdepJQjmYJg9hML3zcBe9ylsboTFonWN+psUeLh8TY2vvsCO3 +IbYe92XxAeccSsjRFSDp1MudskxXtKhLDuNbVBYQUTs/r1Hp49B9HqMwWd2OjLVp +Al2jXjcCIgXibQS4+ysz1VnJ4550WWWyfwPlDN2TYhpVlE1c4b3MmRkEYQIDAQAB +AoGAGiCCr56XUOJxwpmamN8E2zauz5kEWK9gPt1GnaOo9Clj1H5zLBOO0BWlV9mE +rO+HRSemtrFsbVv4tCjud2Yohp2yAAe8nnW33Xf4KDLZ62wtP5HCXaIoNZKmTnpC +QHc2I/k674jUGE4tCvrYwg0CJQQrpTpXizA8YECudxZ48okCQQD9gKVPdlBeEsF2 +OVKHF//n1LI6+2cD9sWoPzdXayVcpemDyTl+GIQYhqZDVWsMj6DvfOHHlNZdYGr2 +XrmCbvCvAkEA25peZpnAnnwcqgKUrbaNKq5rmYPtbdu5I6rloMUs/OiO2lHkXs9Q +QN904G1dTYOcaEOVH5nMuwD04Es/7Lj/7wJBALE9SddV9Hjhiivbhiz4Ba8UUgzV +C0CFP8sTb+EKA9RUGAFRJoZYI7t2ITcAuNjObwoieUVudbZRnFdnATMF1/cCQQCF +SEvDOc4OYoWDKc3TINjM7s+ffNK9un3DiBWWXhXP6dXJ66oPYQP0W6s0Cyx1v0tO +fLYlV9NKLGpzNzi1FBNBAkAO4WRyZXBK9BVBLyfJq77uptlLZW71yl2X1oSklFyM +MpLH4u1SJorRypt7MsxPgcF4pAZSs/TWaCmx8nmSBcEE +-----END RSA PRIVATE KEY----- diff --git a/tests/cert-svc/data/rootcert.pem b/tests/cert-svc/data/rootcert.pem new file mode 100644 index 0000000..5c3ef72 --- /dev/null +++ b/tests/cert-svc/data/rootcert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDgTCCAuqgAwIBAgIJAMU+zh6oJmrXMA0GCSqGSIb3DQEBBQUAMIGIMQswCQYD +VQQGEwJLUjEUMBIGA1UECBMLS3l1bmctZ2kgZG8xEjAQBgNVBAcTCVN1LXdvbiBz +aTEQMA4GA1UEChMHU2Ftc3VuZzEMMAoGA1UECxMDRE1DMRAwDgYDVQQDEwdDQSBj +ZXJ0MR0wGwYJKoZIhvcNAQkBFg5jYUBzYW1zdW5nLmNvbTAeFw0xMTAzMjkwMjQ1 +MzhaFw0xMjAzMjgwMjQ1MzhaMIGIMQswCQYDVQQGEwJLUjEUMBIGA1UECBMLS3l1 +bmctZ2kgZG8xEjAQBgNVBAcTCVN1LXdvbiBzaTEQMA4GA1UEChMHU2Ftc3VuZzEM +MAoGA1UECxMDRE1DMRAwDgYDVQQDEwdDQSBjZXJ0MR0wGwYJKoZIhvcNAQkBFg5j +YUBzYW1zdW5nLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwTDwxz9h +2KaO4X29eKQxT3XCNRMnzSpx62rNLLGaXYrOMYHQcUDOkwEFRw4fV4yxqXgwk7Bv +4C+anNX2jN6SkYGEj4mGDVrE0jaI60X04tf3fAb0Ltw2PEgKsB56X75PNAxGP8oh +/y6fysoCAEyNhoYnwEsRrSfWY8iAm+hKAxUCAwEAAaOB8DCB7TAdBgNVHQ4EFgQU +zWrq4lSmi+wjKZjZlyDpjVOxkYUwgb0GA1UdIwSBtTCBsoAUzWrq4lSmi+wjKZjZ +lyDpjVOxkYWhgY6kgYswgYgxCzAJBgNVBAYTAktSMRQwEgYDVQQIEwtLeXVuZy1n +aSBkbzESMBAGA1UEBxMJU3Utd29uIHNpMRAwDgYDVQQKEwdTYW1zdW5nMQwwCgYD +VQQLEwNETUMxEDAOBgNVBAMTB0NBIGNlcnQxHTAbBgkqhkiG9w0BCQEWDmNhQHNh +bXN1bmcuY29tggkAxT7OHqgmatcwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUF +AAOBgQB6dqH4U00mnavG0bUVTjhEwYbdQtpSc+fKB3+O9QY4PlLttyd3GfeKmsxe +Z2RwUtUd3vjEDNPROcDAow6bHdy4B++qoojKVj1INJI0iDG/i6NUnDofsH+NS7mW +J6FKF6ukwnTfk2HjvIfrLO6S8nSVa1dSoB2GHzg2kWgm36a9pw== +-----END CERTIFICATE----- diff --git a/tests/cert-svc/data/signing/chain1.crt b/tests/cert-svc/data/signing/chain1.crt new file mode 100644 index 0000000..a80bbbc --- /dev/null +++ b/tests/cert-svc/data/signing/chain1.crt @@ -0,0 +1,52 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=AU, ST=Some-State, L=root, O=Internet Widgits Pty Ltd, OU=root, CN=root/emailAddress=root + Validity + Not Before: May 13 01:21:41 2011 GMT + Not After : May 12 01:21:41 2012 GMT + Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, OU=chain1, CN=chain1/emailAddress=chain1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:ae:6d:d3:18:3f:b2:63:ab:fb:72:ce:ff:9a:8b: + 07:4a:52:c5:99:0e:9e:5c:68:ce:82:67:07:7a:27: + 11:98:a7:fe:3a:68:3f:4e:4b:74:d4:a5:77:15:87: + 7e:9c:9f:10:82:2f:1c:e3:c0:c7:1e:8b:35:ab:3a: + f6:13:44:81:43:22:a7:fa:06:36:9c:55:53:7a:9d: + 18:9b:a0:f4:93:58:50:2c:cd:ab:ec:32:2f:fa:4f: + ff:6e:6a:68:75:15:76:e1:b1:e1:67:f9:13:0a:d0: + 9b:db:12:b9:fd:dd:51:19:e4:63:d0:d0:56:b5:6a: + 00:a5:03:68:e7:77:21:b0:f9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + 01:d3:3c:dc:a0:62:14:99:b8:b1:99:cf:0c:4a:50:2b:f7:1e: + 56:f6:de:ce:80:b4:32:bb:0c:5c:45:b7:78:e5:27:ee:90:0c: + a0:db:ef:32:85:85:08:c6:4a:e6:22:7b:56:61:d5:b4:4e:a1: + 7e:ed:60:c2:bf:bc:51:89:9a:b1:73:c2:e0:bb:3d:4e:fa:6f: + 3e:32:b5:7f:b4:bc:0f:8a:ca:7d:f0:bf:da:b1:12:23:0e:cc: + 57:e5:58:7c:23:38:b1:d8:b2:13:d8:6a:0d:20:bd:e9:66:51: + 2d:e6:57:a1:33:17:69:6d:21:9f:18:37:23:6c:ca:0e:b0:c4: + 47:86 +-----BEGIN CERTIFICATE----- +MIICjDCCAfWgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBhzELMAkGA1UEBhMCQVUx +EzARBgNVBAgTClNvbWUtU3RhdGUxDTALBgNVBAcTBHJvb3QxITAfBgNVBAoTGElu +dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDENMAsGA1UECxMEcm9vdDENMAsGA1UEAxME +cm9vdDETMBEGCSqGSIb3DQEJARYEcm9vdDAeFw0xMTA1MTMwMTIxNDFaFw0xMjA1 +MTIwMTIxNDFaMH4xCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw +HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAsTBmNoYWlu +MTEPMA0GA1UEAxMGY2hhaW4xMRUwEwYJKoZIhvcNAQkBFgZjaGFpbjEwgZ8wDQYJ +KoZIhvcNAQEBBQADgY0AMIGJAoGBAK5t0xg/smOr+3LO/5qLB0pSxZkOnlxozoJn +B3onEZin/jpoP05LdNSldxWHfpyfEIIvHOPAxx6LNas69hNEgUMip/oGNpxVU3qd +GJug9JNYUCzNq+wyL/pP/25qaHUVduGx4Wf5EwrQm9sSuf3dURnkY9DQVrVqAKUD +aOd3IbD5AgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEA +AdM83KBiFJm4sZnPDEpQK/ceVvbezoC0MrsMXEW3eOUn7pAMoNvvMoWFCMZK5iJ7 +VmHVtE6hfu1gwr+8UYmasXPC4Ls9TvpvPjK1f7S8D4rKffC/2rESIw7MV+VYfCM4 +sdiyE9hqDSC96WZRLeZXoTMXaW0hnxg3I2zKDrDER4Y= +-----END CERTIFICATE----- diff --git a/tests/cert-svc/data/signing/chain1.key b/tests/cert-svc/data/signing/chain1.key new file mode 100644 index 0000000..8fe8106 --- /dev/null +++ b/tests/cert-svc/data/signing/chain1.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCubdMYP7Jjq/tyzv+aiwdKUsWZDp5caM6CZwd6JxGYp/46aD9O +S3TUpXcVh36cnxCCLxzjwMceizWrOvYTRIFDIqf6BjacVVN6nRiboPSTWFAszavs +Mi/6T/9uamh1FXbhseFn+RMK0JvbErn93VEZ5GPQ0Fa1agClA2jndyGw+QIDAQAB +AoGATPoWoKrrlOT/EMmdL5yPWRNyNHupE2sFR7MkL5oyP8ZTgX8kAO933agwB4ZG +L+RaqrkT7MbUmPwicTCSDCq9SCLSL+fQS/hujdRbsBhnLTuAiaIblmpDYO5z6Rma +tUXnImdvKROpYmBNNzFzDlj0686KahdYGXJOTFYSST3QHEkCQQDap3/5ursNj1NY +dehaiUhYD3mOqgrj/MhN+JHNR6Eb3qQQ1Aa/rQmEkPnmopNy7qc/B+6Y4CMxNLkM +bHSyre2/AkEAzDibGZCBct4slqyuPyZTfgh3UQSaCQ4CSF7HG/Pj/ZeHqDnKoxR7 +v//WZy5gxHZ7CrSWM/laNOd6svdtQs1/RwJBAJ1UMK1MQxN6sYnRLSMX7MoQOHMC +v1tUo/wWgzKl+7LF/F9vcHuy0kpk1quxB0+HkSe1WWT+wdPCD/R0hXOb2pkCQFt0 +ehjfuujbEDLF0B6dpkRJvE0+91BYwrLwJtCgzxgQ1QKEJvgTQzv/cV+xyEoTGRT5 +PE64Oyp4A13EKl0BNB8CQF7C0zzEBE/MngPizBU6KEfo47c0hD57IUVGcIA3juwm +AELZem13BOjaDk9CEZppfk1lpdU0ZKmkIodlDwLVgLE= +-----END RSA PRIVATE KEY----- diff --git a/tests/cert-svc/data/signing/chain1pub.pem b/tests/cert-svc/data/signing/chain1pub.pem new file mode 100644 index 0000000..80c3a5f --- /dev/null +++ b/tests/cert-svc/data/signing/chain1pub.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCubdMYP7Jjq/tyzv+aiwdKUsWZ +Dp5caM6CZwd6JxGYp/46aD9OS3TUpXcVh36cnxCCLxzjwMceizWrOvYTRIFDIqf6 +BjacVVN6nRiboPSTWFAszavsMi/6T/9uamh1FXbhseFn+RMK0JvbErn93VEZ5GPQ +0Fa1agClA2jndyGw+QIDAQAB +-----END PUBLIC KEY----- diff --git a/tests/cert-svc/data/signing/msg b/tests/cert-svc/data/signing/msg new file mode 100644 index 0000000..9d8a4e7 --- /dev/null +++ b/tests/cert-svc/data/signing/msg @@ -0,0 +1 @@ +this is test file diff --git a/tests/cert-svc/data/signing/msg.sig b/tests/cert-svc/data/signing/msg.sig new file mode 100644 index 0000000..5139633 --- /dev/null +++ b/tests/cert-svc/data/signing/msg.sig @@ -0,0 +1,3 @@ ++Y‡K~Ÿ³bê”PP[íÀl‘ÈšÚâþ—áyH`3Ã\UŽ A¬oJIˆQO-8®Õ¹¸ +|1m Y· Š2U˜NJ҃ÂîvÍ&Ñïj AƒTÝìñz;î)z«qºÏÂ#<2ÀYŒ4M4îà +!!(°:J˜ \ No newline at end of file diff --git a/tests/cert-svc/data/signing/msg.sig.enc b/tests/cert-svc/data/signing/msg.sig.enc new file mode 100644 index 0000000..fb2c0b8 --- /dev/null +++ b/tests/cert-svc/data/signing/msg.sig.enc @@ -0,0 +1,3 @@ +K1mHS36fs2LqApQRUFATW+3AE2yRyJra4v6X4XlIYDPDXJBVjgxBrG9KSYhRTy04 +j67VubgMCnwxEW0FDJBZtwmKMlWYTkrSg8Luds0bJtHvag1BHYOPVMOd7PF6ExU7 +7il6q3G6z8IjPDLAWRQFjH80TQQENO7gCiEhKLA6Spg= diff --git a/tests/cert-svc/data/signing/msg2 b/tests/cert-svc/data/signing/msg2 new file mode 100644 index 0000000..1af9cc6 --- /dev/null +++ b/tests/cert-svc/data/signing/msg2 @@ -0,0 +1 @@ +this is test2 diff --git a/tests/cert-svc/delete_test.c b/tests/cert-svc/delete_test.c new file mode 100644 index 0000000..68c895d --- /dev/null +++ b/tests/cert-svc/delete_test.c @@ -0,0 +1,102 @@ +#include +#include + +#include "cert-service.h" + +#define RELATIVE_PATH "./data/Broot.der" +#define ABSOLUTE_PATH "./data/Broot.der" // for target + +int tcase_1_success() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + + // delete 'Broot.der' from '.../code-signing/java/operator' + ret = cert_svc_delete_certificate_from_store("Broot.der", "code-signing_java_operator"); + if(ret == CERT_SVC_ERR_NO_ERROR) { + if((access("/opt/share/cert-svc/certs/code-signing/java/operator/Broot.der", F_OK)) != 0) + return 0; + else + return -1; + } + else + return -1; +} + +int tcase_2_success() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + + // delete 'Broot.der' from '.../ssl' + ret = cert_svc_delete_certificate_from_store("Broot.der", NULL); + if(ret == CERT_SVC_ERR_NO_ERROR) { + if((access("/opt/share/cert-svc/certs/ssl/Broot.der", F_OK)) != 0) + return 0; + else + return -1; + } + else + return -1; +} + +int tcase_3_fail() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + + // delete NULL + ret = cert_svc_delete_certificate_from_store(NULL, "code-signing_java_operator"); + if(ret == CERT_SVC_ERR_INVALID_PARAMETER) + return 0; + else + return -1; +} + +int tcase_4_fail() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + + // delete 'Broot.der' from invalid directory + ret = cert_svc_delete_certificate_from_store("Broot.der", "code-signing_debian"); + if(ret == CERT_SVC_ERR_FILE_IO) + return 0; + else + return -1; +} + +int main(void) +{ + int ret = -1; + + // store test files + cert_svc_add_certificate_to_store(RELATIVE_PATH, "code-signing_java_operator"); + cert_svc_add_certificate_to_store(RELATIVE_PATH, NULL); + + // test case 1 : success + ret = tcase_1_success(); + if(ret == 0) + fprintf(stdout, "** Success to delete test 1 - testpath: code-signing **\n"); + else + fprintf(stdout, "** Fail to delete test1 **\n"); + + // test case 2 : success - no location (ssl) + ret = tcase_2_success(); + if(ret == 0) + fprintf(stdout, "** Success to delete test 2 - testpath: ssl **\n"); + else + fprintf(stdout, "** Fail to delete test2 **\n"); + + // test case 3 : fail - no filename + ret = tcase_3_fail(); + if(ret == 0) + fprintf(stdout, "** Success to delete test 3 - no filename **\n"); + else + fprintf(stdout, "** Fail to delete test3 **\n"); + + // test case 4 : fail - invalid dir name + ret = tcase_4_fail(); + if(ret == 0) + fprintf(stdout, "** Success to delete test 4 - invalid dir path **\n"); + else + fprintf(stdout, "** Fail to delete test4 **\n"); + + return 0; +} diff --git a/tests/cert-svc/extract_test.c b/tests/cert-svc/extract_test.c new file mode 100644 index 0000000..eb1f2a5 --- /dev/null +++ b/tests/cert-svc/extract_test.c @@ -0,0 +1,175 @@ +#include +#include +#include + +#include "cert-service.h" + +#define DER_CERT "./data/Broot.pem" +#define PEM_CERT "./data/Broot.der" +#define PFX_CERT "./data/pfx/temp/server.pfx" +#define INVALID_CERT "./data/invalidCert.der" + +int tcase_1_success() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + CERT_CONTEXT* ctx = NULL; + + // initialize cert context + ctx = cert_svc_cert_context_init(); + + // load certificate file to buffer + if((ret = cert_svc_load_file_to_context(ctx, DER_CERT)) != CERT_SVC_ERR_NO_ERROR) + goto err; + + // extract certificate data + if((ret = cert_svc_extract_certificate_data(ctx)) != CERT_SVC_ERR_NO_ERROR) + goto err; + +err: + // finalize cert context + cert_svc_cert_context_final(ctx); + return ret; +} + +int tcase_2_success() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + CERT_CONTEXT* ctx = NULL; + + // initialize cert context + ctx = cert_svc_cert_context_init(); + + // load certificate file to buffer + if((ret = cert_svc_load_file_to_context(ctx, PEM_CERT)) != CERT_SVC_ERR_NO_ERROR) + goto err; + + // extract certificate data + if((ret = cert_svc_extract_certificate_data(ctx)) != CERT_SVC_ERR_NO_ERROR) + goto err; + +err: + // finalize cert context + cert_svc_cert_context_final(ctx); + return ret; +} + +int tcase_3_success() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + CERT_CONTEXT* ctx = NULL; + unsigned char* prikey = NULL; + char* pass = "test\0"; + + // initialize cert context + ctx = cert_svc_cert_context_init(); + + // load certificate file to buffer + if((ret = cert_svc_load_PFX_file_to_context(ctx, &prikey, PFX_CERT, pass)) != CERT_SVC_ERR_NO_ERROR) + goto err; + printf(" ****** prikey: [%s]\n", prikey); + + // extract certificate data + if((ret = cert_svc_extract_certificate_data(ctx)) != CERT_SVC_ERR_NO_ERROR) + goto err; + +err: + // finalize cert context + cert_svc_cert_context_final(ctx); + if(prikey != NULL) + free(prikey); + return ret; +} + +int tcase_4_fail() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + CERT_CONTEXT* ctx = NULL; + + // initialize cert context + ctx = cert_svc_cert_context_init(); + + // extract certificate data + if((ret = cert_svc_extract_certificate_data(ctx)) != CERT_SVC_ERR_INVALID_PARAMETER) + goto err; + ret = CERT_SVC_ERR_NO_ERROR; + +err: + // finalize cert context + cert_svc_cert_context_final(ctx); + return ret; +} + +int tcase_5_fail() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + CERT_CONTEXT* ctx = NULL; + + // initialize cert context + ctx = cert_svc_cert_context_init(); + + // load certificate file to buffer + if((ret = cert_svc_load_file_to_context(ctx, INVALID_CERT)) != CERT_SVC_ERR_NO_ERROR) + goto err; + + // extract certificate data + if((ret = cert_svc_extract_certificate_data(ctx)) != CERT_SVC_ERR_INVALID_CERTIFICATE) + goto err; + ret = CERT_SVC_ERR_NO_ERROR; + +err: + // finalize cert context + cert_svc_cert_context_final(ctx); + return ret; +} + +int main(int argc, char* argv[]) +{ + int ret = -1; + + // store test certificate + cert_svc_add_certificate_to_store(DER_CERT, NULL); + cert_svc_add_certificate_to_store(PEM_CERT, NULL); + cert_svc_add_certificate_to_store(PFX_CERT, NULL); + + // extract test - success: PEM + ret = tcase_1_success(); + if(ret == 0) + fprintf(stdout, "** Success to extract certificate: DER type **\n"); + else + fprintf(stdout, "** Fail to extract certificate: DER type **\n"); + + // extract test - success: DER + ret = tcase_2_success(); + if(ret == 0) + fprintf(stdout, "** Success to extract certificate: PEM type **\n"); + else + fprintf(stdout, "** Fail to extract certificate: PEM type **\n"); + + // extract test - success: PFX + ret = tcase_3_success(); + if(ret == 0) + fprintf(stdout, "** Success to extract certificate: PFX type **\n"); + else + fprintf(stdout, "** Fail to extract certificate: PFX type **\n"); + + // extract test - fail: no file + ret = tcase_4_fail(); + if(ret == 0) + fprintf(stdout, "** Success to extract certificate: no certificate **\n"); + else + fprintf(stdout, "** Fail to extract certificate: no certificate **\n"); + + // extract test - fail: invalid certificate + ret = tcase_5_fail(); + if(ret == 0) + fprintf(stdout, "** Success to extract certificate: invalid certificate **\n"); + else + fprintf(stdout, "** Fail to extract certificate: invalid certificate **\n"); + + // delete test certificate + cert_svc_delete_certificate_from_store("Broot.pem", NULL); + cert_svc_delete_certificate_from_store("Broot.der", NULL); + cert_svc_delete_certificate_from_store("server.pfx", NULL); + + return 0; +} diff --git a/tests/cert-svc/extract_test_pfx.c b/tests/cert-svc/extract_test_pfx.c new file mode 100644 index 0000000..5869c1b --- /dev/null +++ b/tests/cert-svc/extract_test_pfx.c @@ -0,0 +1,111 @@ +#include +#include +#include + +#include "cert-service.h" + +int main(int argc, char* argv[]) +{ + int ret = CERT_SVC_ERR_NO_ERROR; + CERT_CONTEXT* ctx = NULL; + cert_svc_cert_descriptor* certDesc = NULL; + int i = 0, keyLen = 0; + int extNum = 0, j = 0; +// unsigned char* prikey = NULL; + + ctx = cert_svc_cert_context_init(); + + if((ret = cert_svc_load_file_to_context(ctx, argv[1])) != CERT_SVC_ERR_NO_ERROR) { + printf("file: [%s]\n", argv[1]); + printf("*** Fail to load file, ret: [%d]\n", ret); + } +// if((ret = cert_svc_load_PFX_file_to_context(ctx, &prikey, argv[1], "test")) != CERT_SVC_ERR_NO_ERROR) { +// printf("file: [%s]\n", argv[1]); +// printf("*** Fail to load file, ret: [%d]\n", ret); +// } + + if((ret = cert_svc_extract_certificate_data(ctx)) != CERT_SVC_ERR_NO_ERROR) + printf("*** Fail to extract certificate, ret: [%d]\n", ret); + +// printf("private key: [%s]\n", prikey); + + certDesc = ctx->certDesc; + + printf("type: [%s]\n", certDesc->type); + printf("version: [%d]\n", certDesc->info.version); + printf("serial number: [%d]\n", certDesc->info.serialNumber); + printf("signature algorithm: [%s]\n", certDesc->info.sigAlgo); + printf("issuer: [%s]\n", certDesc->info.issuerStr); + printf(" country name: [%s]\n", certDesc->info.issuer.countryName); + printf(" state or province name: [%s]\n", certDesc->info.issuer.stateOrProvinceName); + printf(" locality name: [%s]\n", certDesc->info.issuer.localityName); + printf(" organization name: [%s]\n", certDesc->info.issuer.organizationName); + printf(" organization unit name: [%s]\n", certDesc->info.issuer.organizationUnitName); + printf(" common name: [%s]\n", certDesc->info.issuer.commonName); + printf(" email address: [%s]\n", certDesc->info.issuer.emailAddress); + printf("validity:\n"); + printf(" not before: [%d].[%d].[%d]/[%d]:[%d]:[%d]\n", certDesc->info.validPeriod.firstYear, + certDesc->info.validPeriod.firstMonth, + certDesc->info.validPeriod.firstDay, + certDesc->info.validPeriod.firstHour, + certDesc->info.validPeriod.firstMinute, + certDesc->info.validPeriod.firstSecond); + printf(" not after: [%d].[%d].[%d]/[%d]:[%d]:[%d]\n", certDesc->info.validPeriod.secondYear, + certDesc->info.validPeriod.secondMonth, + certDesc->info.validPeriod.secondDay, + certDesc->info.validPeriod.secondHour, + certDesc->info.validPeriod.secondMinute, + certDesc->info.validPeriod.secondSecond); + printf("subject: [%s]\n", certDesc->info.subjectStr); + printf(" country name: [%s]\n", certDesc->info.subject.countryName); + printf(" state or province name: [%s]\n", certDesc->info.subject.stateOrProvinceName); + printf(" locality name: [%s]\n", certDesc->info.subject.localityName); + printf(" organization name: [%s]\n", certDesc->info.subject.organizationName); + printf(" organization unit name: [%s]\n", certDesc->info.subject.organizationUnitName); + printf(" common name: [%s]\n", certDesc->info.subject.commonName); + printf(" email address: [%s]\n", certDesc->info.subject.emailAddress); +// printf("public key:\n"); +// keyLen = certDesc->info.pubKeyLen; +// printf(" algorithm: [%s]\n", certDesc->info.pubKeyAlgo); +// printf(" key:\n"); +// for(i = 0; i < keyLen; i++) { +// printf("%02X", certDesc->info.pubKey[i]); +// if(i < (keyLen - 1)) +// printf(":"); +// if(((i+1) % 10) == 0) +// printf("\n"); +// } +// printf("\n"); +// printf("issuer UID: [%s]\n", certDesc->info.issuerUID); +// printf("subject UID: [%s]\n", certDesc->info.subjectUID); +// +// printf("extensions:\n"); +// extNum = certDesc->ext.numOfFields; +// for(i = 0; i < extNum; i++) { +// printf(" field : [%s]\n", certDesc->ext.fields[i].name); +// printf(" data : "); +// for(j = 0; j < certDesc->ext.fields[i].datasize; j++) { +// printf("%02X", certDesc->ext.fields[i].data[j]); +// if(j < (certDesc->ext.fields[i].datasize - 1)) +// printf(":"); +// } +// printf("\n"); +// } +// +// printf("signature:\n"); +// printf(" signature algorithm: [%s]\n", certDesc->signatureAlgo); +// printf(" signature data:\n"); +// for(i = 0; i < certDesc->signatureLen; i++) { +// printf("%02X", certDesc->signatureData[i]); +// if(i < (certDesc->signatureLen - 1)) +// printf(":"); +// if(((i+1) % 10) == 0) +// printf("\n"); +// } +// printf("\n"); + + if((ret = cert_svc_cert_context_final(ctx)) != CERT_SVC_ERR_NO_ERROR) + printf("*** Fail to finalize context, ret: [%d]\n", ret); + + return ret; +} diff --git a/tests/cert-svc/mem_test.c b/tests/cert-svc/mem_test.c new file mode 100644 index 0000000..501d015 --- /dev/null +++ b/tests/cert-svc/mem_test.c @@ -0,0 +1,39 @@ +#include +#include +#include + +#include "cert-service.h" + +#define CERT_FILE "./data/Broot.pem" +#define PFX_FILE "./data/pfx/pfxtest.pfx" + +int main() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + CERT_CONTEXT* ctx = NULL; + unsigned char* prikey = NULL; + char* passp = NULL; + + // initialize + ctx = cert_svc_cert_context_init(); + + // file load +// ret = cert_svc_load_file_to_context(ctx, CERT_FILE); + ret = cert_svc_load_PFX_file_to_context(ctx, &prikey, PFX_FILE, passp); + if(ret != CERT_SVC_ERR_NO_ERROR) + printf("\n!!!! FILE LOAD ERROR !!!!\n"); + + // extract +// ret = cert_svc_extract_certificate_data(ctx); +// if(ret != CERT_SVC_ERR_NO_ERROR) +// printf("\n!!!! EXTRACT CERT ERROR !!!!\n"); + + // finalize + if(prikey != NULL) + free(prikey); + ret = cert_svc_cert_context_final(ctx); + if(ret != CERT_SVC_ERR_NO_ERROR) + printf("\n!!!! CONTEXT FINAL ERROR !!!!\n"); + + return 0; +} diff --git a/tests/cert-svc/search_test.c b/tests/cert-svc/search_test.c new file mode 100644 index 0000000..4f20bde --- /dev/null +++ b/tests/cert-svc/search_test.c @@ -0,0 +1,40 @@ +#include +#include +#include + +#include "cert-service.h" + +int main(int argc, char* argv[]) +{ + int ret = CERT_SVC_ERR_NO_ERROR; + search_field fldNo = ISSUER_EMAILADDRESS; + char* fldData = "EmailR"; + cert_svc_filename_list* start = NULL; + CERT_CONTEXT* ctx = NULL; + + ctx = cert_svc_cert_context_init(); + + ret = cert_svc_search_certificate(ctx, fldNo, fldData); + if(ret != CERT_SVC_ERR_NO_ERROR) { + printf("[ERROR] error no: [%d]\n", ret); + goto err; + } + else { + start = ctx->fileNames; + if(start == NULL) { + printf("Cannot find any certificate.\n"); + goto err; + } + + while(1) { + printf("filename: [%s]\n", start->filename); + if(start->next == NULL) + break; + start = start->next; + } + } + +err: + cert_svc_cert_context_final(ctx); + return 0; +} diff --git a/tests/cert-svc/store_test.c b/tests/cert-svc/store_test.c new file mode 100644 index 0000000..e669945 --- /dev/null +++ b/tests/cert-svc/store_test.c @@ -0,0 +1,118 @@ +#include +#include + +#include "cert-service.h" + +#define RELATIVE_PATH "./data/Broot.der" +#define ABSOLUTE_PATH "./data/Broot.der" + +int tcase_1_success() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + + // store relative path + ret = cert_svc_add_certificate_to_store(RELATIVE_PATH, "code-signing_java_thirdparty"); + if(ret == CERT_SVC_ERR_NO_ERROR) { + if((access("/opt/share/cert-svc/certs/code-signing/java/thirdparty/Broot.der", F_OK)) != 0) // fail + return -1; + else + return 0; + } + else + return -1; + + // store absolute path - only be in target +} + +int tcase_2_success() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + + // store into default path + ret = cert_svc_add_certificate_to_store(RELATIVE_PATH, NULL); + if(ret == CERT_SVC_ERR_NO_ERROR) { + if((access("/opt/share/cert-svc/certs/ssl/Broot.der", F_OK)) != 0) // fail + return -1; + else + return 0; + } + else + return -1; +} + +int tcase_3_fail() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + + // store NULL + ret = cert_svc_add_certificate_to_store(NULL, "code-signing_wac"); + if(ret == CERT_SVC_ERR_INVALID_PARAMETER) + return 0; + else + return -1; +} + +int tcase_4_fail() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + + // store into invalid directory + ret = cert_svc_add_certificate_to_store(RELATIVE_PATH, "code-signing_debian"); + if(ret == CERT_SVC_ERR_FILE_IO) + return 0; + else + return -1; +} + +int finalize_test() +{ + // delete files which be stored during testing + if((unlink("/opt/share/cert-svc/certs/code-signing/java/thirdparty/Broot.der")) != 0) // fail + return -1; + if((unlink("/opt/share/cert-svc/certs/ssl/Broot.der")) != 0) // fail + return -1; + + return 0; +} + +int main(void) +{ + int ret = -1; + + // test case 1 : success + ret = tcase_1_success(); + if(ret == 0) + fprintf(stdout, "** Success to store test 1 - testpath: code_signing **\n"); + else + fprintf(stdout, "** Fail to store test 1 **\n"); + + // test case 2 : success - no location (ssl) + ret = tcase_2_success(); + if(ret == 0) + fprintf(stdout, "** Success to store test 2 - testpath: ssl **\n"); + else + fprintf(stdout, "** Fail to store test 2 **\n"); + + // test case 3 : fail - no filename + ret = tcase_3_fail(); + if(ret == 0) + fprintf(stdout, "** Success to store test 3 - no filename **\n"); + else + fprintf(stdout, "** Fail to store test 3 **\n"); + + // test case 4 : fail - invalid dir name + ret = tcase_4_fail(); + if(ret == 0) + fprintf(stdout, "** Success to store test 4 - invalid dir path **\n"); + else + fprintf(stdout, "** Fail to store test 4 **\n"); + + // test finalize + ret = finalize_test(); + if(ret == 0) + fprintf(stdout, "** Finalize store test **\n"); + else + fprintf(stdout, "** Fail to finalize store test, ret: [%d] **\n", ret); + + return 0; +} diff --git a/tests/cert-svc/verify_sig.c b/tests/cert-svc/verify_sig.c new file mode 100644 index 0000000..98a088d --- /dev/null +++ b/tests/cert-svc/verify_sig.c @@ -0,0 +1,86 @@ +#include +#include +#include + +#include "cert-service.h" + +#define CERT_PATH "./data/signing/chain1.crt" +#define MSG_PATH "./data/signing/msg" +//#define SIG_PATH "./data/signing/msg.sig" +#define SIG_PATH "./data/signing/msg.sig.enc" + +int main(int argc, char* argv[]) +{ + int ret = CERT_SVC_ERR_NO_ERROR; + int validity = 0; + CERT_CONTEXT* ctx = NULL; + unsigned char* msg = NULL; + int msgLen = 0; + unsigned char* sig = NULL; + unsigned char* tmpSig = NULL; + int sigLen = 0; + FILE* fp_msg = NULL; + FILE* fp_sig = NULL; + int i = 0, j = 0; + + ctx = cert_svc_cert_context_init(); + + // load certificate + if((ret = cert_svc_load_file_to_context(ctx, CERT_PATH)) != CERT_SVC_ERR_NO_ERROR) { + printf("Fail to load file to buffer, [%s]\n", CERT_PATH); + goto err; + } + + // load message + if(!(fp_msg = fopen(MSG_PATH, "rb"))) { + printf("Fail to open file, [%s]\n", MSG_PATH); + goto err; + } + fseek(fp_msg, 0L, SEEK_END); + msgLen = ftell(fp_msg); + fseek(fp_msg, 0L, SEEK_SET); + + msg = (unsigned char*)malloc(sizeof(unsigned char) * (msgLen + 1)); + memset(msg, 0x00, (msgLen + 1)); + fread(msg, sizeof(unsigned char), msgLen, fp_msg); + + // load signature + if(!(fp_sig = fopen(SIG_PATH, "rb"))) { + printf("Fail to open file, [%s]\n", SIG_PATH); + goto err; + } + fseek(fp_sig, 0L, SEEK_END); + sigLen = ftell(fp_sig); + fseek(fp_sig, 0L, SEEK_SET); + + sig = (unsigned char*)malloc(sizeof(unsigned char) * (sigLen + 1)); + tmpSig = (unsigned char*)malloc(sizeof(unsigned char) * (sigLen + 1)); + memset(sig, 0x00, (sigLen + 1)); + memset(tmpSig, 0x00, (sigLen + 1)); + + fread(sig, sizeof(unsigned char), sigLen, fp_sig); + for(i = 0; i < sigLen; i++) { + if(sig[i] != '\n') { + tmpSig[j] = sig[i]; + j++; + } + } + + // function call +// if((ret = cert_svc_verify_signature(ctx, msg, sig, sigLen, "SHA1", &validity)) != CERT_SVC_ERR_NO_ERROR) { + if((ret = cert_svc_verify_signature(ctx, msg, msgLen, tmpSig, NULL, &validity)) != CERT_SVC_ERR_NO_ERROR) { + printf("Fail to verify signature.\n"); + goto err; + } + printf("[RESULT] ret: [%d]\n", validity); + +err: + if(fp_msg != NULL) fclose(fp_msg); + if(fp_sig != NULL) fclose(fp_sig); + if(msg != NULL) free(msg); + if(sig != NULL) free(sig); + if(tmpSig != NULL) free(tmpSig); + cert_svc_cert_context_final(ctx); + + return 0; +} diff --git a/tests/cert-svc/verify_test.c b/tests/cert-svc/verify_test.c new file mode 100644 index 0000000..4dbe9c6 --- /dev/null +++ b/tests/cert-svc/verify_test.c @@ -0,0 +1,66 @@ +#include +#include +#include + +#include "cert-service.h" + +#define TARGET_CERT "./data/cert_chain/server.crt" +#define CHAIN1_CERT "./data/cert_chain/chain1.crt" +#define CHAIN2_CERT "./data/cert_chain/chain2.crt" +#define CHAIN3_CERT "./data/cert_chain/chain3.crt" +#define CHAIN4_CERT "./data/cert_chain/chain4.crt" +#define CHAIN5_CERT "./data/cert_chain/chain5.crt" + +int main() +{ + int ret = CERT_SVC_ERR_NO_ERROR; + int validity = 0; + CERT_CONTEXT* ctx = cert_svc_cert_context_init(); + + // load certificate to context +// if((ret = cert_svc_load_file_to_context(ctx, TARGET_CERT)) != CERT_SVC_ERR_NO_ERROR) { + if((ret = cert_svc_load_file_to_context(ctx, CHAIN1_CERT)) != CERT_SVC_ERR_NO_ERROR) { + printf("ERR!! ret: [%d]\n", ret); + goto err; + } + + // push certificates to context +// if((ret = cert_svc_push_file_into_context(ctx, CHAIN1_CERT)) != CERT_SVC_ERR_NO_ERROR) { +// printf("ERR!! ret: [%d]\n", ret); +// goto err; +// } +// if((ret = cert_svc_push_file_into_context(ctx, CHAIN2_CERT)) != CERT_SVC_ERR_NO_ERROR) { +// printf("ERR!! ret: [%d]\n", ret); +// goto err; +// } +// if((ret = cert_svc_push_file_into_context(ctx, CHAIN5_CERT)) != CERT_SVC_ERR_NO_ERROR) { +// printf("ERR!! ret: [%d]\n", ret); +// goto err; +// } +// if((ret = cert_svc_push_file_into_context(ctx, CHAIN4_CERT)) != CERT_SVC_ERR_NO_ERROR) { +// printf("ERR!! ret: [%d]\n", ret); +// goto err; +// } +// if((ret = cert_svc_push_file_into_context(ctx, CHAIN3_CERT)) != CERT_SVC_ERR_NO_ERROR) { +// printf("ERR!! ret: [%d]\n", ret); +// goto err; +// } +// +// // check linked list +// if(ctx->certLink == NULL) { +// printf("FAIL!!\n"); +// goto err; +// } + + // verify + ret = cert_svc_verify_certificate(ctx, &validity); + if(ret != CERT_SVC_ERR_NO_ERROR) + printf("ret: [%d]\n", ret); + + printf("[RESULT] validity: [%d]\n", validity); + printf("[RESULT] root CA path: [%s]\n", ctx->fileNames->filename); + +err: + cert_svc_cert_context_final(ctx); + return 0; +} diff --git a/tests/pkcs12/CMakeLists.txt b/tests/pkcs12/CMakeLists.txt new file mode 100644 index 0000000..cca4bbf --- /dev/null +++ b/tests/pkcs12/CMakeLists.txt @@ -0,0 +1,71 @@ +# Copyright (c) 2011 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 CMakeLists.txt +# @author Jacek Migacz (j.migacz@samsung.com) +# @version 1.0 +# @brief This package provides bacis check of internal OpenSSL's PKCS#12 routines. +# +INCLUDE(FindPkgConfig) +SET(TARGET_PKCS12_TEST "cert-svc-tests-pkcs12") + +PKG_CHECK_MODULES(PKCS12_TEST_DEP + libsoup-2.4 + dpl-test-efl + dpl-db-efl + libpcrecpp + secure-storage + REQUIRED + ) + +SET(PKCS12_TEST_SOURCES + ${PROJECT_SOURCE_DIR}/tests/pkcs12/pkcs12_test.cpp + ${PROJECT_SOURCE_DIR}/tests/pkcs12/test_cases.cpp + ) + +INCLUDE_DIRECTORIES( + ${PROJECT_SOURCE_DIR}/vcore/src + ${PROJECT_SOURCE_DIR}/tests/pkcs12 + ${PKCS12_TEST_DEP_INCLUDE_DIRS} + ${VCOREC_TEST_DEP_INCLUDE_DIRS} + ) + +ADD_EXECUTABLE(${TARGET_PKCS12_TEST} ${PKCS12_TEST_SOURCES}) + +ADD_DEFINITIONS("-DDPL_LOGS_ENABLED") + +TARGET_LINK_LIBRARIES(${TARGET_PKCS12_TEST} + ${TARGET_PKCS12_TEST_LIB} + ${PKCS12_TEST_DEP_LIBRARIES} + ${TARGET_VCORE_LIB} + ${VCOREC_TEST_DEP_LIBRARIES} + ) + +INSTALL(TARGETS ${TARGET_PKCS12_TEST} + DESTINATION /usr/bin + PERMISSIONS OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE + ) + +INSTALL(FILES + ${PROJECT_SOURCE_DIR}/tests/pkcs12/test.p12 + ${PROJECT_SOURCE_DIR}/tests/pkcs12/with_pass.p12 + ${PROJECT_SOURCE_DIR}/tests/pkcs12/without_pass.p12 + DESTINATION /opt/apps/widget/tests/pkcs12/ +) diff --git a/tests/pkcs12/pkcs12_test.cpp b/tests/pkcs12/pkcs12_test.cpp new file mode 100644 index 0000000..95debc4 --- /dev/null +++ b/tests/pkcs12/pkcs12_test.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 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 pkcs12_test.cpp + * @author Jacek Migacz (j.migacz@samsung.com) + * @version 1.0 + * @brief PKCS#12 test runner. + */ +#include +#include + +CertSvcInstance vinstance; + +int main (int argc, char *argv[]) { + certsvc_instance_new(&vinstance); + int status = DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv); + certsvc_instance_free(vinstance); + return status; +} diff --git a/tests/pkcs12/test.p12 b/tests/pkcs12/test.p12 new file mode 100644 index 0000000..e5c2db8 Binary files /dev/null and b/tests/pkcs12/test.p12 differ diff --git a/tests/pkcs12/test_cases.cpp b/tests/pkcs12/test_cases.cpp new file mode 100644 index 0000000..94b5e1e --- /dev/null +++ b/tests/pkcs12/test_cases.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011 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_cases.cpp + * @author Jacek Migacz (j.migacz@samsung.com) + * @version 1.0 + * @brief PKCS#12 test cases. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static CertSvcInstance instance; + +#define CREATE_INSTANCE \ + certsvc_instance_new(&instance); +#define FREE_INSTANCE \ + certsvc_instance_free(instance); + +RUNNER_TEST(test01_import_and_remove_pkcs12_container) { + const char path[] = "/opt/apps/widget/tests/pkcs12/test.p12"; + const char pass[] = "zaq12WSX"; + char tmpn[L_tmpnam], *alias; + int result; + + CREATE_INSTANCE + CertSvcString Alias, Path, Pass; + RUNNER_ASSERT_MSG((tmpnam(tmpn)), "tmpnam(3) failed.."); + alias = strrchr(tmpn, '/'); + ++alias; + RUNNER_ASSERT_MSG(alias && *alias, "Invalid alias."); + Alias.privateHandler = (char *)alias; + Alias.privateLength = strlen(alias); + Pass.privateHandler = (char *)pass; + Pass.privateLength = strlen(pass); + Path.privateHandler = (char *)path; + Path.privateLength = strlen(path); + result = certsvc_pkcs12_import_from_file(instance, Path, Pass, Alias); + RUNNER_ASSERT_MSG(result == CERTSVC_SUCCESS, "certsvc_pkcs12_import_from_file failed."); + + int is_unique; + result = certsvc_pkcs12_alias_exists(instance, Alias, &is_unique); + RUNNER_ASSERT_MSG(result == CERTSVC_SUCCESS && !is_unique, "certsvc_pkcs12_alias_exists failed."); + + char *buf; + int size; + result = certsvc_pkcs12_private_key_dup(instance, Alias, &buf, &size); + RUNNER_ASSERT_MSG(result == CERTSVC_SUCCESS, "certsvc_pkcs12_private_key_dup failed."); + certsvc_pkcs12_private_key_free(buf); + + result = certsvc_pkcs12_delete(instance, Alias); + RUNNER_ASSERT_MSG(result == CERTSVC_SUCCESS, "certsvc_pkcs12_delete failed."); + FREE_INSTANCE +} + +RUNNER_TEST(test02_pkcs12_has_password) { + const char with[] = "/opt/apps/widget/tests/pkcs12/with_pass.p12"; + int has_pwd = 0; + + CREATE_INSTANCE + CertSvcString File; + File.privateHandler = (char *)with; + File.privateLength = strlen(with); + int result = certsvc_pkcs12_has_password(instance, File, &has_pwd); + FREE_INSTANCE + + RUNNER_ASSERT_MSG(result == CERTSVC_SUCCESS && has_pwd == CERTSVC_TRUE, "Error quering pkcs12/pfx container password."); +} + +RUNNER_TEST(test03_pkcs12_has_password) { + const char without[] = "/opt/apps/widget/tests/pkcs12/without_pass.p12"; + int has_pwd = 0; + + CREATE_INSTANCE + CertSvcString File; + File.privateHandler = (char *)without; + File.privateLength = strlen(without); + int result = certsvc_pkcs12_has_password(instance, File, &has_pwd); + FREE_INSTANCE + + RUNNER_ASSERT_MSG(result == CERTSVC_SUCCESS && has_pwd == CERTSVC_FALSE, "Error quering pkcs12/pfx container password."); +} diff --git a/tests/pkcs12/with_pass.p12 b/tests/pkcs12/with_pass.p12 new file mode 100644 index 0000000..b8b1d34 Binary files /dev/null and b/tests/pkcs12/with_pass.p12 differ diff --git a/tests/pkcs12/without_pass.p12 b/tests/pkcs12/without_pass.p12 new file mode 100644 index 0000000..4b58ba9 Binary files /dev/null and b/tests/pkcs12/without_pass.p12 differ diff --git a/tests/vcore/CMakeLists.txt b/tests/vcore/CMakeLists.txt new file mode 100644 index 0000000..375383b --- /dev/null +++ b/tests/vcore/CMakeLists.txt @@ -0,0 +1,135 @@ +# Copyright (c) 2011 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 CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @author Pawel Sikorski (p.sikorski@samsung.com) +# @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +SET(TARGET_VCORE_TEST "cert-svc-tests-vcore") + +PKG_CHECK_MODULES(VCORE_TEST_DEP + libsoup-2.4 + dpl-test-efl + dpl-db-efl + libpcrecpp + REQUIRED + ) + +SET(VCORE_TESTS_SOURCES + ${PROJECT_SOURCE_DIR}/tests/vcore/vcore_tests.cpp + ${PROJECT_SOURCE_DIR}/tests/vcore/TestCases.cpp + ${PROJECT_SOURCE_DIR}/tests/vcore/TestEnv.cpp + ${PROJECT_SOURCE_DIR}/tests/vcore/TestCRL.cpp + ${PROJECT_SOURCE_DIR}/tests/vcore/file_input_mapping.cpp + ) + +INCLUDE_DIRECTORIES( + ${PROJECT_SOURCE_DIR}/vcore/src + ${PROJECT_SOURCE_DIR}/tests/vcore + ${VCORE_TEST_DEP_INCLUDE_DIRS} + ) + +ADD_DEFINITIONS("-DDPL_LOGS_ENABLED") + +ADD_EXECUTABLE(${TARGET_VCORE_TEST} ${VCORE_TESTS_SOURCES}) + +TARGET_LINK_LIBRARIES(${TARGET_VCORE_TEST} + ${SYS_EFL_LIBRARIES} + ${TARGET_VCORE_LIB} + ${VCORE_TEST_DEP_LIBRARIES} + ) + +INSTALL(TARGETS ${TARGET_VCORE_TEST} + DESTINATION /usr/bin + PERMISSIONS OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE + ) + +INSTALL(FILES ${PROJECT_SOURCE_DIR}/tests/vcore/cert-svc-tests-vcore-ocsp-server.sh + DESTINATION /usr/bin + PERMISSIONS OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE + ) + +ADD_CUSTOM_COMMAND(TARGET ${TARGET_VCORE_TEST} POST_BUILD + COMMAND ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/create_certs.sh + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/ + COMMENT "Generate certificate chains" + ) + +INSTALL(FILES + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/widget/author-signature.xml + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/widget/signature1.xml + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/widget/signature22.xml + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/widget/config.xml + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/widget/index.html + DESTINATION + /opt/apps/widget/tests/vcore_widget_uncompressed + ) + +INSTALL(FILES + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/keys/ocsp_level0deprecated.crt + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/keys/ocsp_level1.crt + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/keys/ocsp_level2.crt + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/keys/ocsp_rootca.crt + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/keys/operator.root.cert.pem + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/keys/root_cacert0.pem + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/keys/CAbundle.crt + DESTINATION + /opt/apps/widget/tests/vcore_keys + ) + +INSTALL(FILES + ${PROJECT_SOURCE_DIR}/tests/vcore/test-cases/keys/root_cacert0.pem + DESTINATION + /opt/share/cert-svc/certs/code-signing/wac/root_cacert0.pem + ) + +INSTALL(FILES + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/demoCA/cacert.pem + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/1second_level.pem + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/1third_level.pem + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/2second_level.pem + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/2third_level.pem + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/3second_level.pem + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/3third_level.pem + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/cacrl1.pem + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/cacrl2.pem + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/respcert.pem + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/respcert.key + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/openssl.cnf + DESTINATION + /opt/apps/widget/tests/vcore_certs/ +) + +INSTALL(DIRECTORY + ${PROJECT_SOURCE_DIR}/tests/vcore/certificate-generator/demoCA + DESTINATION + /opt/apps/widget/tests/vcore_certs/ +) + diff --git a/tests/vcore/TestCRL.cpp b/tests/vcore/TestCRL.cpp new file mode 100644 index 0000000..7c798d1 --- /dev/null +++ b/tests/vcore/TestCRL.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011 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. + */ +#include +#include +#include +#include +#include +#include "TestCRL.h" + +using namespace ValidationCore; +using namespace std; + + +namespace { +const char *CRL_LOOKUP_DIR = "/opt/etc/ssl/certs/"; +const char *beginCertificate = "-----BEGIN CERTIFICATE-----"; +const char *endCertificate = "-----END CERTIFICATE-----"; +const char *beginTrustedCertificate = "-----BEGIN TRUSTED CERTIFICATE-----"; +const char *endTrustedCertificate = "-----END TRUSTED CERTIFICATE-----"; + + +bool whiteCharacter(char a){ + return a == '\n'; +} + +} + +TestCRL::TestCRL() + : CRL(new CRLCacheDAO) +{ + //Add additional lookup dir + int rv = X509_LOOKUP_add_dir(m_lookup, CRL_LOOKUP_DIR, X509_FILETYPE_PEM); + if (!rv) { + LogError("Failed to add lookup dir for PEM files."); + ThrowMsg(CRLException::StorageError, + "Failed to add lookup dir for PEM files."); + } + LogInfo("CRL storage initialization complete."); +} + +std::string TestCRL::getFileContent(const std::string &filename) +{ + //Only PEM formatted files allowed + LogInfo("Read file: " << filename); + FileInputMapping file(filename); + string content(reinterpret_cast(file.GetAddress()), + file.GetSize()); + + size_t posBegin = content.find(beginCertificate); + size_t posEnd = content.find(endCertificate); + if (posBegin != string::npos && + posEnd != string::npos) { + posBegin += strlen(beginCertificate); + } else { + posBegin = content.find(beginTrustedCertificate); + posEnd = content.find(endTrustedCertificate); + if (posBegin != string::npos && + posEnd != string::npos) { + posBegin += strlen(beginTrustedCertificate); + } else { + LogError("Failed to parse PEM file"); + return string(); + } + } + //Remove whitespaces + string cert(content, posBegin, posEnd - posBegin); + cert.erase(std::remove_if(cert.begin(), cert.end(), whiteCharacter), + cert.end()); + + return cert; +} + +void TestCRL::addCRLToStore(const string &filename, const string &uri) +{ + LogInfo("Read file: " << filename); + //Only PEM formatted files allowed + FileInputMapping file(filename); + char *buffer = new char[file.GetSize()]; + memcpy(buffer, file.GetAddress(), file.GetSize()); + CRLDataPtr crl(new CRLData(buffer, file.GetSize(), uri)); + updateCRL(crl); +} diff --git a/tests/vcore/TestCRL.h b/tests/vcore/TestCRL.h new file mode 100644 index 0000000..9b9b5cc --- /dev/null +++ b/tests/vcore/TestCRL.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 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. + */ +#ifndef _TEST_CRL_H +#define _TEST_CRL_H + +#include +#include +#include + +class TestCRL : public ValidationCore::CRL +{ + public: + TestCRL(); + + void addCRLToStore(const std::string &filename, const std::string &uri); + + //convinient function + std::string getFileContent(const std::string &filename); +}; + +#endif diff --git a/tests/vcore/TestCases.cpp b/tests/vcore/TestCases.cpp new file mode 100644 index 0000000..daba37c --- /dev/null +++ b/tests/vcore/TestCases.cpp @@ -0,0 +1,1337 @@ +/* + * Copyright (c) 2011 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. + */ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "TestEnv.h" +#include +#include +#include +#include +#include +#include +#include "TestCRL.h" +#include + +namespace { + +const std::string widget_path = + "/opt/apps/widget/tests/vcore_widget_uncompressed/"; +const std::string keys_path = "/opt/apps/widget/tests/vcore_keys/"; +const std::string widget_store_path = "/opt/apps/widget/tests/vcore_widgets/"; +const std::string cert_store_path = "/opt/apps/widget/tests/vcore_certs/"; +const std::string crl_URI = "http://localhost/my.crl"; + +const std::string anka_ec_key_type = "urn:oid:1.2.840.10045.3.1.7"; +const std::string anka_ec_public_key = + "BGi9RmTUjpqCpQjx6SSiKdfmtjQBFNSN7ghm6TuaH9r4x73WddeLxLioH3VEmFLC+QLiR"\ + "kPxDxL/6YmQdgfGrqk="; + +const std::string rsa_modulus = + "ocwjKEFaPxLNcPTz2PtT2Gyu5jzkWaPo4thjZo3rXuNbD4TzjY02UGnTxvflNeORLpSS1"\ + "PeYr/1E/Nhr7qQAzj9g0DwW7p8zQEdOUi3v76VykeB0pFJH+0Fxp6LVBX9Z+EvZk+dbOy"\ + "GJ4Njm9B6M09axXlV11Anj9B/HYUDfDX8="; +const std::string rsa_exponent = "AQAB"; + +const std::string magda_dsa_p = + "2BYIQj0ePUVxzrdBT41eCblraa9Dqag7QXFMCRM2PtyS22JPDKuV77tBc/jg0V3htHWdR"\ + "q9n6/kQDwrP7FIPoLATLIiC3oAYWj46Mr6d9k/tt/JZU6PvULmB2k1wrrmvKUi+U+I5Ro"\ + "qe8ui8lqR9pp9u2WCh2QmFfCohKNjN5qs="; +const std::string magda_dsa_q = "4p4JcDqz+S7CbWyd8txApZw0sik="; +const std::string magda_dsa_g = + "AQrLND1ZGFvzwBpPPXplmPh1ijPx1O2gQEvPvyjR88guWcGqQc0m7dTb6PEvbI/oZ0o91"\ + "k7VEkfthURnNR1WtOLT8dmAuKQfwTQLPwCwUM/QiuWSlCyKLTE4Ev8aOG7ZqWudsKm/td"\ + "n9pUNGtcod1wo1ZtP7PfEJ6rYZGQDOlz8="; + +const std::string googleCA = +"MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG" +"A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz" +"cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2" +"MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV" +"BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt" +"YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN" +"ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE" +"BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is" +"I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G" +"CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do" +"lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc" +"AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k"; + +const std::string google2nd = +"MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV" +"UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi" +"bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw" +"MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh" +"d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD" +"QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx" +"PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g" +"5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo" +"3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG" +"A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX" +"BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov" +"L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG" +"AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF" +"BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB" +"BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc" +"q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR" +"bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv"; + +const std::string google3rd = +"MIIDIjCCAougAwIBAgIQK59+5colpiUUIEeCdTqbuTANBgkqhkiG9w0BAQUFADBM" +"MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg" +"THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x" +"MzA5MzAyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh" +"MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRgw" +"FgYDVQQDFA9tYWlsLmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ" +"AoGBAK85FZho5JL+T0/xu/8NLrD+Jaq9aARnJ+psQ0ynbcvIj36B7ocmJRASVDOe" +"qj2bj46Ss0sB4/lKKcMP/ay300yXKT9pVc9wgwSvLgRudNYPFwn+niAkJOPHaJys" +"Eb2S5LIbCfICMrtVGy0WXzASI+JMSo3C2j/huL/3OrGGvvDFAgMBAAGjgecwgeQw" +"DAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLnRoYXd0" +"ZS5jb20vVGhhd3RlU0dDQ0EuY3JsMCgGA1UdJQQhMB8GCCsGAQUFBwMBBggrBgEF" +"BQcDAgYJYIZIAYb4QgQBMHIGCCsGAQUFBwEBBGYwZDAiBggrBgEFBQcwAYYWaHR0" +"cDovL29jc3AudGhhd3RlLmNvbTA+BggrBgEFBQcwAoYyaHR0cDovL3d3dy50aGF3" +"dGUuY29tL3JlcG9zaXRvcnkvVGhhd3RlX1NHQ19DQS5jcnQwDQYJKoZIhvcNAQEF" +"BQADgYEANYARzVI+hCn7wSjhIOUCj19xZVgdYnJXPOZeJWHTy60i+NiBpOf0rnzZ" +"wW2qkw1iB5/yZ0eZNDNPPQJ09IHWOAgh6OKh+gVBnJzJ+fPIo+4NpddQVF4vfXm3" +"fgp8tuIsqK7+lNfNFjBxBKqeecPStiSnJavwSI4vw6e7UN0Pz7A="; + +const std::string certVerisign = +"MIIG+DCCBeCgAwIBAgIQU9K++SSnJF6DygHkbKokdzANBgkqhkiG9w0BAQUFADCB" +"vjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL" +"ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2Ug" +"YXQgaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykwNjE4MDYGA1UEAxMv" +"VmVyaVNpZ24gQ2xhc3MgMyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNTTCBTR0MgQ0Ew" +"HhcNMTAwNTI2MDAwMDAwWhcNMTIwNTI1MjM1OTU5WjCCASkxEzARBgsrBgEEAYI3" +"PAIBAxMCVVMxGTAXBgsrBgEEAYI3PAIBAhMIRGVsYXdhcmUxGzAZBgNVBA8TElYx" +"LjAsIENsYXVzZSA1LihiKTEQMA4GA1UEBRMHMjQ5Nzg4NjELMAkGA1UEBhMCVVMx" +"DjAMBgNVBBEUBTk0MDQzMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHFA1N" +"b3VudGFpbiBWaWV3MSIwIAYDVQQJFBk0ODcgRWFzdCBNaWRkbGVmaWVsZCBSb2Fk" +"MRcwFQYDVQQKFA5WZXJpU2lnbiwgSW5jLjEmMCQGA1UECxQdIFByb2R1Y3Rpb24g" +"U2VjdXJpdHkgU2VydmljZXMxGTAXBgNVBAMUEHd3dy52ZXJpc2lnbi5jb20wggEi" +"MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCj+PvvK+fZOXwno0yT/OTy2Zm9" +"ehnZjTtO/X2IWBEa3jG30C52uHFQI4NmXiQVNvJHkBaAj0ilVjvGdxXmkyyFsugt" +"IWOTZ8pSKdX1tmGFIon6Ko9+lBFkVkudA1ogAUbtTB8IcdeOlpK78T4SjdVMhY18" +"150YzSw6hRKlw52wBaDxtGZElvOth41K7TUcaDnQVzz5SBPW5MUhi7AWrdoSk17O" +"BozOzmB/jkYDVDnwLcbR89SLHEOle/idSYSDQUmab3y0JS8RyQV1+DB70mnFALnD" +"fLiL47nMQQCGxXgp5voQ2YmSXhevKmEJ9vvtC6C7yv2W6yomfS/weUEce9pvAgMB" +"AAGjggKCMIICfjCBiwYDVR0RBIGDMIGAghB3d3cudmVyaXNpZ24uY29tggx2ZXJp" +"c2lnbi5jb22CEHd3dy52ZXJpc2lnbi5uZXSCDHZlcmlzaWduLm5ldIIRd3d3LnZl" +"cmlzaWduLm1vYmmCDXZlcmlzaWduLm1vYmmCD3d3dy52ZXJpc2lnbi5ldYILdmVy" +"aXNpZ24uZXUwCQYDVR0TBAIwADAdBgNVHQ4EFgQU8oBwK/WBXCZDWi0dbuDgPyTK" +"iJIwCwYDVR0PBAQDAgWgMD4GA1UdHwQ3MDUwM6AxoC+GLWh0dHA6Ly9FVkludGwt" +"Y3JsLnZlcmlzaWduLmNvbS9FVkludGwyMDA2LmNybDBEBgNVHSAEPTA7MDkGC2CG" +"SAGG+EUBBxcGMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNv" +"bS9ycGEwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUFBwMCBglghkgBhvhCBAEw" +"HwYDVR0jBBgwFoAUTkPIHXbvN1N6T/JYb5TzOOLVvd8wdgYIKwYBBQUHAQEEajBo" +"MCsGCCsGAQUFBzABhh9odHRwOi8vRVZJbnRsLW9jc3AudmVyaXNpZ24uY29tMDkG" +"CCsGAQUFBzAChi1odHRwOi8vRVZJbnRsLWFpYS52ZXJpc2lnbi5jb20vRVZJbnRs" +"MjAwNi5jZXIwbgYIKwYBBQUHAQwEYjBgoV6gXDBaMFgwVhYJaW1hZ2UvZ2lmMCEw" +"HzAHBgUrDgMCGgQUS2u5KJYGDLvQUjibKaxLB4shBRgwJhYkaHR0cDovL2xvZ28u" +"dmVyaXNpZ24uY29tL3ZzbG9nbzEuZ2lmMA0GCSqGSIb3DQEBBQUAA4IBAQB9VZxB" +"wDMRGyhFWYkY5rwUVGuDJiGeas2xRJC0G4+riQ7IN7pz2a2BhktmZ5HbxXL4ZEY4" +"yMN68DEVErhtKiuL02ng27alhlngadKQzSL8pLdmQ+3jEwm9nva5C/7pbeqy+qGF" +"is4IWNYOc4HKNkABxXm5v0ouys8HPNkTLFLep0gLqRXW3gYN2XbKUWMs7z7hJpkY" +"GxP8YQSxi513O2dWVCXB8S6erIz9E/bcfdXoCPyQdn42y3IEoJvPvBS3S55fD4+Q" +"Q43GPhumSg9a6S3hnyw8DX5OiUGmqgQrtSeDRsNmWqtWizEQbe+fotZpEn/7zYTa" +"tk1ni/k5jDH/QeuG"; + +const std::string crlExampleCertificate = +"MIIFlDCCBHygAwIBAgIBADANBgkqhkiG9w0BAQUFADBDMRIwEAYKCZImiZPyLGQB" +"GRYCZXMxGDAWBgoJkiaJk/IsZAEZFghpcmlzZ3JpZDETMBEGA1UEAxMKSVJJU0dy" +"aWRDQTAeFw0wNTA2MjgwNTAyMjhaFw0xNTA2MjYwNTAyMjhaMEMxEjAQBgoJkiaJ" +"k/IsZAEZFgJlczEYMBYGCgmSJomT8ixkARkWCGlyaXNncmlkMRMwEQYDVQQDEwpJ" +"UklTR3JpZENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1CQiWlff" +"ajoMSTuismKqLQ+Mt33Tq4bBpCZvCBXhqan1R0ksILPtK1L7C8QWqPk6AZZpuNmY" +"cNVtJGc8ksgDWvX0EB3GKwZTZ8RrSRlSEe9Otq+Ur7S9uxM1JMmCr6zZTMFANzBS" +"4btnduV78C09IhFYG4OW8IPhNrbfPaeOR+PRPAa/qdSONAwTrM1sZkIvGpAkBWM6" +"Pn7TK9BAK6GLvwgii780fWj3Cwgmp8EDCTievBbWj+z8/apMEy9R0vyB2dWNNCnk" +"6q8VvrjgMsJt33O3BqOoBuZ8R/SS9OFWLFSU3s7cfrRaUSJk/Mx8OGFizRkcXSzX" +"0Nidcg7hX5i78wIDAQABo4ICkTCCAo0wDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E" +"FgQUnUJkLlupXvH/bMg8NtPxtkOYrRowawYDVR0jBGQwYoAUnUJkLlupXvH/bMg8" +"NtPxtkOYrRqhR6RFMEMxEjAQBgoJkiaJk/IsZAEZFgJlczEYMBYGCgmSJomT8ixk" +"ARkWCGlyaXNncmlkMRMwEQYDVQQDEwpJUklTR3JpZENBggEAMA4GA1UdDwEB/wQE" +"AwIBxjARBglghkgBhvhCAQEEBAMCAAcwOwYJYIZIAYb4QgENBC4WLElSSVNHcmlk" +"IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IENlcnRpZmljYXRlMIGZBgNVHR8EgZEw" +"gY4wLqAsoCqGKGh0dHA6Ly93d3cuaXJpc2dyaWQuZXMvcGtpL2NybC9jYWNybC5w" +"ZW0wXKBaoFiGVmxkYXA6Ly9sZGFwLmlyaXNncmlkLmVzOjEzODAvY249SVJJU0dy" +"aWRDQSxkYz1pcmlzZ3JpZCxkYz1lcz9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0" +"MDcGCWCGSAGG+EIBAwQqFihodHRwOi8vd3d3LmlyaXNncmlkLmVzL3BraS9jcmwv" +"Y2FjcmwucGVtME4GCWCGSAGG+EIBCARBFj9odHRwOi8vd3d3LmlyaXNncmlkLmVz" +"L3BraS9wb2xpY3kvMS4zLjYuMS40LjEuNzU0Ny4yLjIuNC4xLjEuMS8waQYDVR0g" +"BGIwYDBeBg0rBgEEAbp7AgIEAQEBME0wSwYIKwYBBQUHAgEWP2h0dHA6Ly93d3cu" +"aXJpc2dyaWQuZXMvcGtpL3BvbGljeS8xLjMuNi4xLjQuMS43NTQ3LjIuMi40LjEu" +"MS4xLzANBgkqhkiG9w0BAQUFAAOCAQEAaqRfyLER+P2QOZLLdz66m7FGsgtFsAEx" +"wiNrIChFWfyHVZG7Ph1fn/GDD5LMsrU23lx3NBN5/feHuut1XNYKNs8vtV07D70r" +"DKjUlPbmWV0B+/GDxe1FDGop/tKQfyHSUaBuauXChFU/2INu5lhBerNl7QxNJ1ws" +"cWGiT7R+L/2EjgzWgH1V/0zmIOMep6kY7MUs8rlyF0O5MNFs232cA1trl9kvhAGU" +"9p58Enf5DWMrh17SPH586yIJeiWZtPez9G54ftY+XIqfn0X0zso0dnoXNJQYS043" +"/5vSnoHdRx/EmN8yjeEavZtC48moN0iJ38eB44uKgCD77rZW5s1XqA=="; + +//class TestCleanup +//{ +// public: +// explicit TestCleanup(bool bCheckForFakeVerification = false) +// { +// if (bCheckForFakeVerification) { +// bool bUnsetEnvVar = true; +// +// m_strEnvVar = "CHECK_ONLY_DOMAIN_INSTEAD_OF_VALIDATION"; +// if (getenv(m_strEnvVar.c_str()) != NULL) { +// bUnsetEnvVar = false; +// } else { +// setenv(m_strEnvVar.c_str(), "1", 0); +// } +// } +// } +// +// ~TestCleanup() +// { +// if (!m_strRootCAPath.empty()) { +// removeCertGivenByFilename(m_strRootCAPath.c_str()); +// } +// +// if (!m_strEnvVar.empty()) { +// unsetenv(m_strEnvVar.c_str()); +// } +// } +// +// void setRootCAPath(const std::string& strRootCAPath) +// { +// m_strRootCAPath = strRootCAPath; +// } +// +// private: +// std::string m_strRootCAPath; +// std::string m_strEnvVar; +//}; +// +//class PolicyChanger : public DPL::Event::EventListener +//{ +// public: +// PolicyChanger() +// { +// DPL::Event::EventDeliverySystem::AddListener(this); +// } +// +// ~PolicyChanger() +// { +// DPL::Event::EventDeliverySystem::RemoveListener(this); +// } +// +// void OnEventReceived(const AceUpdateResponseEvent& event) +// { +// if (0 != event.GetArg0()) { +// LogError("Policy change failed"); +// } +// Assert(0 == event.GetArg0() && "Policy change failed"); +// LoopControl::finish_wait_for_wrt_init(); +// } +// +// void updatePolicy(const std::string& path) +// { +// AceUpdateRequestEvent event(path); +// DPL::Event::EventDeliverySystem::Publish(event); +// LoopControl::wait_for_wrt_init(); +// } +//}; + +} // namespace anonymous + +using namespace ValidationCore; + +////////////////////////////////////////////////// +//////// VALIDATION CORE TEST SUITE //////////// +////////////////////////////////////////////////// + +RUNNER_TEST(test01_signature_finder) +{ + SignatureFileInfoSet signatureSet; + SignatureFinder signatureFinder(widget_path); + RUNNER_ASSERT_MSG( + SignatureFinder::NO_ERROR == signatureFinder.find(signatureSet), + "SignatureFinder failed"); + RUNNER_ASSERT_MSG(signatureSet.size() == 3, + "Some signature has not been found"); + + SignatureFileInfo first = *(signatureSet.begin()); + RUNNER_ASSERT_MSG( + std::string("author-signature.xml") == first.getFileName(), + "Author Signature"); + RUNNER_ASSERT_MSG(-1 == first.getFileNumber(), "Wrong signature number."); + first = *(signatureSet.rbegin()); + RUNNER_ASSERT_MSG(std::string("signature22.xml") == first.getFileName(), + "Wrong signature fileName."); + RUNNER_ASSERT_MSG(22 == first.getFileNumber(), "Wrong signature number."); +} + +RUNNER_TEST(test02_signature_reader) +{ + SignatureFileInfoSet signatureSet; + SignatureFinder signatureFinder(widget_path); + RUNNER_ASSERT_MSG( + SignatureFinder::NO_ERROR == signatureFinder.find(signatureSet), + "SignatureFinder failed"); + + SignatureFileInfoSet::reverse_iterator iter = signatureSet.rbegin(); + + for (; iter != signatureSet.rend(); ++iter) { + SignatureData data(widget_path + iter->getFileName(), + iter->getFileNumber()); + SignatureReader xml; + xml.initialize(data, WrtDB::GlobalConfig::GetSignatureXmlSchema()); + xml.read(data); + } +} + +RUNNER_TEST(test03_signature_validator) +{ + SignatureFileInfoSet signatureSet; + SignatureFinder signatureFinder(widget_path); + LogError("Size: " << signatureSet.size()); + RUNNER_ASSERT_MSG( + SignatureFinder::NO_ERROR == signatureFinder.find(signatureSet), + "SignatureFinder failed"); + + SignatureFileInfoSet::reverse_iterator iter = signatureSet.rbegin(); + LogError("Size: " << signatureSet.size()); + for (; iter != signatureSet.rend(); ++iter) { + SignatureData data(widget_path + iter->getFileName(), + iter->getFileNumber()); + SignatureReader xml; + xml.initialize(data, WrtDB::GlobalConfig::GetSignatureXmlSchema()); + xml.read(data); + + SignatureValidator validator( + false, + false, + false); + + if (data.isAuthorSignature()) { + LogError("Author"); + RUNNER_ASSERT_MSG( + SignatureValidator::SIGNATURE_DISREGARD == + validator.check(data, widget_path), + "Validation failed"); + } else { + LogError("Distributor"); + RUNNER_ASSERT_MSG( + SignatureValidator::SIGNATURE_VERIFIED == + validator.check(data, widget_path), + "Validation failed"); + } + } +} + +RUNNER_TEST(test05_signature_reference) +{ + SignatureFileInfoSet signatureSet; + SignatureFinder signatureFinder(widget_path); + RUNNER_ASSERT_MSG( + SignatureFinder::NO_ERROR == signatureFinder.find(signatureSet), + "SignatureFinder failed"); + + SignatureFileInfoSet::reverse_iterator iter = signatureSet.rbegin(); + + for (; iter != signatureSet.rend(); ++iter) { + SignatureData data(widget_path + iter->getFileName(), + iter->getFileNumber()); + SignatureReader xml; + xml.initialize(data, WrtDB::GlobalConfig::GetSignatureXmlSchema()); + xml.read(data); + + SignatureValidator sval( + false, + false, + false); + sval.check(data, widget_path); + + ReferenceValidator val(widget_path); + RUNNER_ASSERT( + ReferenceValidator::NO_ERROR == val.checkReferences(data)); + } +} + +RUNNER_TEST(test07t01_base64) +{ + std::string strraw = "1234567890qwertyuiop[]asdfghjkl;'zxcvbnm,."; + std::string strenc = + "MTIzNDU2Nzg5MHF3ZXJ0eXVpb3BbXWFzZGZnaGprbDsnenhjdmJubSwu"; + + Base64Encoder encoder; + encoder.reset(); + encoder.append(strraw); + encoder.finalize(); + RUNNER_ASSERT_MSG(strenc == encoder.get(), "Error in Base64Encoder."); + + Base64Decoder decoder; + decoder.reset(); + decoder.append(strenc); + RUNNER_ASSERT(decoder.finalize()); + RUNNER_ASSERT_MSG(strraw == decoder.get(), "Error in Base64Decoder."); +} + +RUNNER_TEST(test07t02_base64) +{ + const size_t MAX = 40; + char buffer[MAX]; + for (size_t i = 0; i(i); + } + + std::string raw(&buffer[0], &buffer[MAX]); + + RUNNER_ASSERT(MAX == raw.size()); + + Base64Encoder encoder; + encoder.reset(); + encoder.append(raw); + encoder.finalize(); + std::string enc = encoder.get(); + + Base64Decoder decoder; + decoder.reset(); + decoder.append(enc); + RUNNER_ASSERT(decoder.finalize()); + RUNNER_ASSERT_MSG(raw == decoder.get(), "Error in Base64 conversion."); +} + +RUNNER_TEST(test07t03_base64) +{ + std::string invalid = "1234)"; + + Base64Decoder decoder; + decoder.reset(); + decoder.append(invalid); + RUNNER_ASSERT(false == decoder.finalize()); +} + +RUNNER_TEST(test07t04_base64) +{ + std::string invalid = "12234"; + + Base64Decoder decoder; + decoder.reset(); + + bool exception = false; + Try { + std::string temp = decoder.get(); + } Catch(Base64Decoder::Exception::NotFinalized) { + exception = true; + } + + RUNNER_ASSERT_MSG(exception, "Base64Decoder does not throw error."); +} + +RUNNER_TEST(test08t01_Certificate) +{ + Certificate cert(certVerisign, Certificate::FORM_BASE64); + + DPL::OptionalString result; + + result = cert.getCommonName(Certificate::FIELD_SUBJECT); + RUNNER_ASSERT_MSG(!result.IsNull(), "No common name"); + RUNNER_ASSERT_MSG(*result == DPL::FromUTF8String("www.verisign.com"), + "CommonName mismatch"); + + result = cert.getCommonName(Certificate::FIELD_ISSUER); + RUNNER_ASSERT_MSG(!result.IsNull(), "No common name"); + RUNNER_ASSERT_MSG(result == DPL::FromUTF8String( + "VeriSign Class 3 Extended Validation SSL SGC CA"), + "CommonName mismatch"); + + result = cert.getCountryName(); + RUNNER_ASSERT_MSG(!result.IsNull(), "No country"); + RUNNER_ASSERT_MSG(*result == DPL::FromUTF8String("US"), + "Country mismatch"); +} + +RUNNER_TEST(test08t02_Certificate) +{ + Certificate cert(certVerisign, Certificate::FORM_BASE64); + + Certificate::Fingerprint fin = + cert.getFingerprint(Certificate::FINGERPRINT_SHA1); + + unsigned char buff[20] = { + 0xb9, 0x72, 0x1e, 0xd5, 0x49, + 0xed, 0xbf, 0x31, 0x84, 0xd8, + 0x27, 0x0c, 0xfe, 0x03, 0x11, + 0x19, 0xdf, 0xc2, 0x2b, 0x0a}; + RUNNER_ASSERT_MSG(fin.size() == 20, "Wrong size of fingerprint"); + + for (size_t i = 0; i<20; ++i) { + RUNNER_ASSERT_MSG(fin[i] == buff[i], "Fingerprint mismatch"); + } +} + +RUNNER_TEST(test08t03_Certificate) +{ + Certificate cert(certVerisign, Certificate::FORM_BASE64); + + Certificate::AltNameSet nameSet = cert.getAlternativeNameDNS(); + + RUNNER_ASSERT(nameSet.size() == 8); + + DPL::String str = DPL::FromUTF8String("verisign.com"); + RUNNER_ASSERT(nameSet.find(str) != nameSet.end()); + + str = DPL::FromUTF8String("fake.com"); + RUNNER_ASSERT(nameSet.find(str) == nameSet.end()); + +} + +RUNNER_TEST(test09t01_CertificateCollection) +{ + CertificateList list; + list.push_back(CertificatePtr( + new Certificate(google2nd, Certificate::FORM_BASE64))); + list.push_back(CertificatePtr( + new Certificate(googleCA, Certificate::FORM_BASE64))); + list.push_back(CertificatePtr( + new Certificate(google3rd, Certificate::FORM_BASE64))); + + CertificateCollection collection; + collection.load(list); + + bool exception = false; + + Try { + RUNNER_ASSERT(collection.isChain()); + } Catch (CertificateCollection::Exception::WrongUsage) { + exception = true; + } + + RUNNER_ASSERT_MSG(exception, "Exception expected!"); + + RUNNER_ASSERT_MSG(collection.sort(), "Sort failed"); + + RUNNER_ASSERT(collection.isChain()); + + std::string encoded = collection.toBase64String(); + + collection.clear(); + + RUNNER_ASSERT_MSG(collection.size() == 0, "Function clear failed."); + + collection.load(encoded); + + RUNNER_ASSERT_MSG(collection.sort(), "Sort failed"); + + list = collection.getChain(); + + RUNNER_ASSERT( + DPL::ToUTF8String(*(list.front().Get()->getCommonName())) == + "mail.google.com"); + RUNNER_ASSERT( + DPL::ToUTF8String(*(list.back().Get()->getOrganizationName())) == + "VeriSign, Inc."); +} + +RUNNER_TEST(test51t01_ocsp_validation_negative) +{ + CertificateCacheDAO::clearCertificateCache(); + + CertificateList lOCSPCertificates; + CertificatePtr certificatePtr; + CertificatePtr pCert0; + CertificatePtr pCert1; + CertificatePtr pCert2; + CertificatePtr pRootCert; + std::string caRootPath(keys_path + "ocsp_rootca.crt"), + certLevel0Path(keys_path + "ocsp_level0deprecated.crt"), + certLevel1Path(keys_path + "ocsp_level1.crt"), + certLevel2Path(keys_path + "ocsp_level2.crt"); + + pRootCert = RevocationCheckerBase::loadPEMFile(caRootPath.c_str()); + if (!pRootCert) { + RUNNER_ASSERT_MSG(false, "Couldn't load ocsp_rootca.crt"); + } + lOCSPCertificates.push_back(pRootCert); + + pCert0 = RevocationCheckerBase::loadPEMFile(certLevel0Path.c_str()); + if (!pCert0) { + RUNNER_ASSERT_MSG(false, "Couldn't load ocsp_level0.crt"); + } + lOCSPCertificates.push_back(CertificatePtr(pCert0)); + + pCert1 = RevocationCheckerBase::loadPEMFile(certLevel1Path.c_str()); + if (!pCert1) { + RUNNER_ASSERT_MSG(false, "Couldn't load ocsp_level1.crt"); + } + lOCSPCertificates.push_back(CertificatePtr(pCert1)); + + pCert2 = RevocationCheckerBase::loadPEMFile(certLevel2Path.c_str()); + if (!pCert2) { + RUNNER_ASSERT_MSG(false, "Couldn't load ocsp_level2.crt"); + } + lOCSPCertificates.push_back(CertificatePtr(pCert2)); + + OCSP ocsp; + ocsp.setDigestAlgorithmForCertId(ValidationCore::OCSP::SHA1); + ocsp.setDigestAlgorithmForRequest(ValidationCore::OCSP::SHA1); + + CertificateCollection collection; + collection.load(lOCSPCertificates); + RUNNER_ASSERT(collection.sort()); + CertificateList sorted = collection.getChain(); + + ocsp.setTrustedStore(sorted); + VerificationStatusSet status = ocsp.validateCertificateList(sorted); + + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_CONNECTION_FAILED), + "Caught OCSP connection error from store exception"); + RUNNER_ASSERT_MSG(status.contains(VERIFICATION_STATUS_GOOD), + "Caught OCSP verification error exception"); + RUNNER_ASSERT_MSG(status.contains(VERIFICATION_STATUS_VERIFICATION_ERROR), + "Caught OCSP verification error exception"); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test51t02_ocsp_validation_positive) +{ + CertificateCacheDAO::clearCertificateCache(); + + CertificateList lOCSPCertificates; + CertificatePtr certificatePtr; + CertificatePtr pCert0; + CertificatePtr pCert1; + CertificatePtr pCert2; + CertificatePtr pRootCert; + std::string caRootPath(keys_path + "ocsp_rootca.crt"), + certLevel1Path(keys_path + "ocsp_level1.crt"), + certLevel2Path(keys_path + "ocsp_level2.crt"); + + pRootCert = RevocationCheckerBase::loadPEMFile(caRootPath.c_str()); + if (!pRootCert) { + RUNNER_ASSERT_MSG(false, "Couldn't load ocsp_rootca.crt"); + } + lOCSPCertificates.push_back(pRootCert); + + pCert1 = RevocationCheckerBase::loadPEMFile(certLevel1Path.c_str()); + if (!pCert1) { + RUNNER_ASSERT_MSG(false, "Couldn't load ocsp_level1.crt"); + } + lOCSPCertificates.push_back(CertificatePtr(pCert1)); + + pCert2 = RevocationCheckerBase::loadPEMFile(certLevel2Path.c_str()); + if (!pCert2) { + RUNNER_ASSERT_MSG(false, "Couldn't load ocsp_level2.crt"); + } + lOCSPCertificates.push_back(CertificatePtr(pCert2)); + + OCSP ocsp; + ocsp.setDigestAlgorithmForCertId(ValidationCore::OCSP::SHA1); + ocsp.setDigestAlgorithmForRequest(ValidationCore::OCSP::SHA1); + + CertificateCollection collection; + collection.load(lOCSPCertificates); + RUNNER_ASSERT(collection.sort()); + CertificateList sorted = collection.getChain(); + + ocsp.setTrustedStore(sorted); + VerificationStatusSet status = ocsp.validateCertificateList(sorted); + + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_CONNECTION_FAILED), + "Caught OCSP connection error from store exception"); + RUNNER_ASSERT_MSG(status.contains(VERIFICATION_STATUS_GOOD), + "Caught OCSP verification error exception"); + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_VERIFICATION_ERROR), + "Caught OCSP verification error exception"); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test51t04_ocsp_request) +{ + CertificateList lTrustedCerts; + + lTrustedCerts.push_back(CertificatePtr( + new Certificate(google3rd, Certificate::FORM_BASE64))); + lTrustedCerts.push_back(CertificatePtr( + new Certificate(google2nd, Certificate::FORM_BASE64))); + lTrustedCerts.push_back(CertificatePtr( + new Certificate(googleCA, Certificate::FORM_BASE64))); + + CertificateCollection chain; + chain.load(lTrustedCerts); + chain.sort(); + + OCSP ocsp; + ocsp.setDigestAlgorithmForCertId(OCSP::SHA1); + ocsp.setDigestAlgorithmForRequest(OCSP::SHA1); + ocsp.setTrustedStore(lTrustedCerts); + VerificationStatus result = ocsp.checkEndEntity(chain); + + RUNNER_ASSERT(VERIFICATION_STATUS_GOOD == result); +} + +RUNNER_TEST(test51t05_cached_ocsp_validation_negative) +{ + CertificateCacheDAO::clearCertificateCache(); + + CertificateList lOCSPCertificates; + CertificatePtr certificatePtr; + CertificatePtr pCert0; + CertificatePtr pCert1; + CertificatePtr pCert2; + CertificatePtr pRootCert; + std::string caRootPath(keys_path + "ocsp_rootca.crt"), + certLevel0Path(keys_path + "ocsp_level0deprecated.crt"), + certLevel1Path(keys_path + "ocsp_level1.crt"), + certLevel2Path(keys_path + "ocsp_level2.crt"); + + pRootCert = RevocationCheckerBase::loadPEMFile(caRootPath.c_str()); + RUNNER_ASSERT_MSG(pRootCert, "Couldn't load ocsp_rootca.crt"); + lOCSPCertificates.push_back(pRootCert); + + pCert0 = RevocationCheckerBase::loadPEMFile(certLevel0Path.c_str()); + RUNNER_ASSERT_MSG(pCert0, "Couldn't load ocsp_level0.crt"); + lOCSPCertificates.push_back(CertificatePtr(pCert0)); + + pCert1 = RevocationCheckerBase::loadPEMFile(certLevel1Path.c_str()); + RUNNER_ASSERT_MSG(pCert1, "Couldn't load ocsp_level1.crt"); + lOCSPCertificates.push_back(CertificatePtr(pCert1)); + + pCert2 = RevocationCheckerBase::loadPEMFile(certLevel2Path.c_str()); + RUNNER_ASSERT_MSG(pCert2, "Couldn't load ocsp_level2.crt"); + lOCSPCertificates.push_back(CertificatePtr(pCert2)); + + CachedOCSP ocsp; + + CertificateCollection collection; + collection.load(lOCSPCertificates); + RUNNER_ASSERT(collection.sort()); + + VerificationStatus status = ocsp.check(collection); + + RUNNER_ASSERT_MSG(status != VERIFICATION_STATUS_GOOD, + "Caught OCSP verification error exception"); + + OCSPCachedStatusList respList; + CertificateCacheDAO::getOCSPStatusList(&respList); + unsigned len = respList.size(); + + status = ocsp.check(collection); + + RUNNER_ASSERT_MSG(status != VERIFICATION_STATUS_GOOD, + "Caught OCSP verification error exception"); + + respList.clear(); + CertificateCacheDAO::getOCSPStatusList(&respList); + RUNNER_ASSERT_MSG(respList.size() == len && len > 0, + "Caught OCSP cache error exception"); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test51t06_cached_ocsp_validation_positive) +{ + CertificateCacheDAO::clearCertificateCache(); + + CertificateList lOCSPCertificates; + CertificatePtr certificatePtr; + CertificatePtr pCert0; + CertificatePtr pCert1; + CertificatePtr pCert2; + CertificatePtr pRootCert; + std::string caRootPath(keys_path + "ocsp_rootca.crt"), + certLevel1Path(keys_path + "ocsp_level1.crt"), + certLevel2Path(keys_path + "ocsp_level2.crt"); + + pRootCert = RevocationCheckerBase::loadPEMFile(caRootPath.c_str()); + RUNNER_ASSERT_MSG(pRootCert, "Couldn't load ocsp_rootca.crt"); + lOCSPCertificates.push_back(pRootCert); + + pCert1 = RevocationCheckerBase::loadPEMFile(certLevel1Path.c_str()); + RUNNER_ASSERT_MSG(pCert1, "Couldn't load ocsp_level1.crt"); + lOCSPCertificates.push_back(CertificatePtr(pCert1)); + + pCert2 = RevocationCheckerBase::loadPEMFile(certLevel2Path.c_str()); + RUNNER_ASSERT_MSG(pCert2, "Couldn't load ocsp_level2.crt"); + lOCSPCertificates.push_back(CertificatePtr(pCert2)); + + CachedOCSP ocsp; + + CertificateCollection collection; + collection.load(lOCSPCertificates); + RUNNER_ASSERT(collection.sort()); + + VerificationStatus status = ocsp.check(collection); + + RUNNER_ASSERT_MSG(status == VERIFICATION_STATUS_GOOD, + "Caught OCSP verification error exception"); + + OCSPCachedStatusList respList; + CertificateCacheDAO::getOCSPStatusList(&respList); + unsigned len = respList.size(); + + status = ocsp.check(collection); + + RUNNER_ASSERT_MSG(status == VERIFICATION_STATUS_GOOD, + "Caught OCSP verification error exception"); + + respList.clear(); + CertificateCacheDAO::getOCSPStatusList(&respList); + RUNNER_ASSERT_MSG(respList.size() == len && len > 0, + "Caught OCSP cache error exception"); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test61_crl_test_revocation_no_crl) +{ + //Clear CRL cache so there is no CRL for those certificates URI. + CertificateCacheDAO::clearCertificateCache(); + //Prepare certificate chain + TestCRL crl; + std::string cacertStr(crl.getFileContent(cert_store_path + "cacert.pem")); + std::string certAStr( + crl.getFileContent(cert_store_path + "1second_level.pem")); + std::string certBStr( + crl.getFileContent(cert_store_path + "1third_level.pem")); + + CertificateLoader loader; + CertificateList certList; + CertificateCollection collection; + RUNNER_ASSERT(loader.loadCertificateFromRawData(cacertStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certAStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certBStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + + collection.load(certList); + + CRL::RevocationStatus status = crl.checkCertificateChain(collection); + RUNNER_ASSERT_MSG(status.isCRLValid == false, + "Some certificate have no CRL extension!"); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test62_crl_test_revocation_set1) +{ + CertificateCacheDAO::clearCertificateCache(); + + //Prepare certificate chain + TestCRL crl; + std::string cacertStr(crl.getFileContent(cert_store_path + "cacert.pem")); + std::string certAStr( + crl.getFileContent(cert_store_path + "1second_level.pem")); + std::string certBStr( + crl.getFileContent(cert_store_path + "1third_level.pem")); + crl.addCRLToStore(cert_store_path + "cacrl1.pem", crl_URI); + + CertificateLoader loader; + CertificateList certList; + CertificateCollection collection; + RUNNER_ASSERT(loader.loadCertificateFromRawData(cacertStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certAStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certBStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + + collection.load(certList); + + CRL::RevocationStatus status = crl.checkCertificateChain(collection); + RUNNER_ASSERT(status.isCRLValid); + RUNNER_ASSERT(status.isRevoked); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test63_crl_test_revocation_set1) +{ + CertificateCacheDAO::clearCertificateCache(); + + //Prepare certificate chain + TestCRL crl; + std::string cacertStr(crl.getFileContent(cert_store_path + "cacert.pem")); + std::string certAStr( + crl.getFileContent(cert_store_path + "1second_level.pem")); + std::string certBStr( + crl.getFileContent(cert_store_path + "1third_level.pem")); + crl.addCRLToStore(cert_store_path + "cacrl1.pem", crl_URI); + + CertificateLoader loader; + CertificateList certList; + CertificateCollection collection; + RUNNER_ASSERT(loader.loadCertificateFromRawData(cacertStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certAStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certBStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + + collection.load(certList); + + CRL::RevocationStatus status = crl.checkCertificateChain(collection); + RUNNER_ASSERT(status.isCRLValid); + RUNNER_ASSERT(status.isRevoked); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test64_crl_test_revocation_set2) +{ + CertificateCacheDAO::clearCertificateCache(); + + //Prepare certificate chain + TestCRL crl; + std::string cacertStr(crl.getFileContent(cert_store_path + "cacert.pem")); + std::string certAStr( + crl.getFileContent(cert_store_path + "2second_level.pem")); + std::string certBStr( + crl.getFileContent(cert_store_path + "2third_level.pem")); + crl.addCRLToStore(cert_store_path + "cacrl1.pem", crl_URI); + + CertificateLoader loader; + CertificateList certList; + CertificateCollection collection; + RUNNER_ASSERT(loader.loadCertificateFromRawData(cacertStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certAStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certBStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + + collection.load(certList); + + CRL::RevocationStatus status = crl.checkCertificateChain(collection); + RUNNER_ASSERT(status.isCRLValid); + RUNNER_ASSERT(!status.isRevoked); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test65_crl_test_revocation_set2) +{ + CertificateCacheDAO::clearCertificateCache(); + + //Prepare certificate chain + TestCRL crl; + std::string cacertStr(crl.getFileContent(cert_store_path + "cacert.pem")); + std::string certAStr( + crl.getFileContent(cert_store_path + "2second_level.pem")); + std::string certBStr( + crl.getFileContent(cert_store_path + "2third_level.pem")); + crl.addCRLToStore(cert_store_path + "cacrl2.pem", crl_URI); + + CertificateLoader loader; + CertificateList certList; + CertificateCollection collection; + RUNNER_ASSERT(loader.loadCertificateFromRawData(cacertStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certAStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certBStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + + collection.load(certList); + + CRL::RevocationStatus status = crl.checkCertificateChain(collection); + RUNNER_ASSERT(status.isCRLValid); + RUNNER_ASSERT(status.isRevoked); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test66_crl_update_expired_lists) +{ + CertificateCacheDAO::clearCertificateCache(); + + CertificatePtr rootCA(new Certificate(googleCA, Certificate::FORM_BASE64)); + + CertificateLoader loader; + loader.loadCertificateFromRawData(google2nd); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + TestCRL crl; + crl.addToStore(rootCA); + + RUNNER_ASSERT_MSG( + crl.updateList(loader.getCertificatePtr(), CRL::UPDATE_ON_EXPIRED), + "CRL update on expired succeeded"); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test67_crl_update_lists_on_demand) +{ + CertificateCacheDAO::clearCertificateCache(); + + CertificatePtr rootCA(new Certificate(googleCA, Certificate::FORM_BASE64)); + + CertificateLoader loader; + loader.loadCertificateFromRawData(google2nd); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + TestCRL crl; + crl.addToStore(rootCA); + + RUNNER_ASSERT_MSG( + crl.updateList(loader.getCertificatePtr(), CRL::UPDATE_ON_DEMAND), + "CRL update on demand succeeded"); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test68_cached_crl_test_positive) +{ + CertificateCacheDAO::clearCertificateCache(); + + TestCRL crl; + + std::string cacertStr(crl.getFileContent(cert_store_path + "cacert.pem")); + std::string certAStr( + crl.getFileContent(cert_store_path + "2second_level.pem")); + std::string certBStr( + crl.getFileContent(cert_store_path + "2third_level.pem")); + crl.addCRLToStore(cert_store_path + "cacrl1.pem", crl_URI); + + CertificateLoader loader; + CertificateList certList; + CertificateCollection collection; + RUNNER_ASSERT(loader.loadCertificateFromRawData(cacertStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certAStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certBStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + + collection.load(certList); + + CRL::RevocationStatus status = crl.checkCertificateChain(collection); + + CachedCRL cached; + VerificationStatus cached_status = cached.check(collection); + CRLCachedDataList list; + CertificateCacheDAO::getCRLResponseList(&list); + unsigned len = list.size(); + + RUNNER_ASSERT(status.isCRLValid); + RUNNER_ASSERT(!status.isRevoked && + cached_status == VERIFICATION_STATUS_GOOD); + + cached_status = cached.check(collection); + list.clear(); + CertificateCacheDAO::getCRLResponseList(&list); + + RUNNER_ASSERT(len == list.size()); + RUNNER_ASSERT(!status.isRevoked && + cached_status == VERIFICATION_STATUS_GOOD); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test69_cached_crl_test_negative) +{ + CertificateCacheDAO::clearCertificateCache(); + + //Prepare certificate chain + TestCRL crl; + std::string cacertStr(crl.getFileContent(cert_store_path + "cacert.pem")); + std::string certAStr( + crl.getFileContent(cert_store_path + "2second_level.pem")); + std::string certBStr( + crl.getFileContent(cert_store_path + "2third_level.pem")); + crl.addCRLToStore(cert_store_path + "cacrl2.pem", crl_URI); + + CertificateLoader loader; + CertificateList certList; + CertificateCollection collection; + RUNNER_ASSERT(loader.loadCertificateFromRawData(cacertStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certAStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + RUNNER_ASSERT(loader.loadCertificateFromRawData(certBStr) == + CertificateLoader::NO_ERROR); + RUNNER_ASSERT(!!loader.getCertificatePtr()); + certList.push_back(loader.getCertificatePtr()); + + collection.load(certList); + + CRL::RevocationStatus status = crl.checkCertificateChain(collection); + CachedCRL cached; + VerificationStatus cached_status = cached.check(collection); + CRLCachedDataList list; + CertificateCacheDAO::getCRLResponseList(&list); + unsigned len = list.size(); + + RUNNER_ASSERT(status.isCRLValid); + RUNNER_ASSERT(status.isRevoked && + cached_status == VERIFICATION_STATUS_REVOKED); + + cached_status = cached.check(collection); + list.clear(); + CertificateCacheDAO::getCRLResponseList(&list); + + RUNNER_ASSERT(len == list.size()); + RUNNER_ASSERT(status.isRevoked && + cached_status == VERIFICATION_STATUS_REVOKED); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test70_ocsp_local_validation_positive) +{ + CertificateCacheDAO::clearCertificateCache(); + + CertificateList lOCSPCertificates; + CertificatePtr certificatePtr; + CertificatePtr pCert0; + CertificatePtr pRootCert; + std::string caRootPath(cert_store_path + "cacert.pem"), + certLevel0Path(cert_store_path + "1second_level.pem"); + + pRootCert = RevocationCheckerBase::loadPEMFile(caRootPath.c_str()); + if (!pRootCert) { + RUNNER_ASSERT_MSG(false, "Couldn't load cacert.pem"); + } + lOCSPCertificates.push_back(pRootCert); + + pCert0 = RevocationCheckerBase::loadPEMFile(certLevel0Path.c_str()); + if (!pCert0) { + RUNNER_ASSERT_MSG(false, "Couldn't load 1second_level.pem"); + } + lOCSPCertificates.push_back(CertificatePtr(pCert0)); + + OCSP ocsp; + ocsp.setDigestAlgorithmForCertId(ValidationCore::OCSP::SHA1); + ocsp.setDigestAlgorithmForRequest(ValidationCore::OCSP::SHA1); + + CertificateCollection collection; + collection.load(lOCSPCertificates); + RUNNER_ASSERT(collection.sort()); + CertificateList sorted = collection.getChain(); + + ocsp.setTrustedStore(sorted); + VerificationStatusSet status = ocsp.validateCertificateList(sorted); + + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_CONNECTION_FAILED), + "Caught OCSP connection error - check if " + "wrt-tests-vcore-ocsp-server.sh is running!"); + RUNNER_ASSERT_MSG(status.contains(VERIFICATION_STATUS_GOOD), + "Caught OCSP verification error exception"); + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_VERIFICATION_ERROR), + "Caught OCSP verification error exception"); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test71_ocsp_local_validation_positive) +{ + CertificateCacheDAO::clearCertificateCache(); + + CertificateList lOCSPCertificates; + CertificatePtr certificatePtr; + CertificatePtr pCert0; + CertificatePtr pRootCert; + std::string caRootPath(cert_store_path + "cacert.pem"), + certLevel0Path(cert_store_path + "3second_level.pem"); + + pRootCert = RevocationCheckerBase::loadPEMFile(caRootPath.c_str()); + if (!pRootCert) { + RUNNER_ASSERT_MSG(false, "Couldn't load cacert.pem"); + } + lOCSPCertificates.push_back(pRootCert); + + pCert0 = RevocationCheckerBase::loadPEMFile(certLevel0Path.c_str()); + if (!pCert0) { + RUNNER_ASSERT_MSG(false, "Couldn't load 3second_level.pem"); + } + lOCSPCertificates.push_back(CertificatePtr(pCert0)); + + OCSP ocsp; + ocsp.setDigestAlgorithmForCertId(ValidationCore::OCSP::SHA1); + ocsp.setDigestAlgorithmForRequest(ValidationCore::OCSP::SHA1); + + CertificateCollection collection; + collection.load(lOCSPCertificates); + RUNNER_ASSERT(collection.sort()); + CertificateList sorted = collection.getChain(); + + ocsp.setTrustedStore(sorted); + VerificationStatusSet status = ocsp.validateCertificateList(sorted); + + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_CONNECTION_FAILED), + "Caught OCSP connection error - check if " + "wrt-tests-vcore-ocsp-server.sh is running!"); + RUNNER_ASSERT_MSG(status.contains(VERIFICATION_STATUS_GOOD), + "Caught OCSP verification error exception"); + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_VERIFICATION_ERROR), + "Caught OCSP verification error exception"); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test72_ocsp_local_validation_revoked) +{ + CertificateCacheDAO::clearCertificateCache(); + + CertificateList lOCSPCertificates; + CertificatePtr certificatePtr; + CertificatePtr pCert0; + CertificatePtr pRootCert; + std::string caRootPath(cert_store_path + "cacert.pem"), + certLevel0Path(cert_store_path + "2second_level.pem"); + + pRootCert = RevocationCheckerBase::loadPEMFile(caRootPath.c_str()); + if (!pRootCert) { + RUNNER_ASSERT_MSG(false, "Couldn't load cacert.pem"); + } + lOCSPCertificates.push_back(pRootCert); + + pCert0 = RevocationCheckerBase::loadPEMFile(certLevel0Path.c_str()); + if (!pCert0) { + RUNNER_ASSERT_MSG(false, "Couldn't load 2second_level.pem"); + } + lOCSPCertificates.push_back(CertificatePtr(pCert0)); + + OCSP ocsp; + ocsp.setDigestAlgorithmForCertId(ValidationCore::OCSP::SHA1); + ocsp.setDigestAlgorithmForRequest(ValidationCore::OCSP::SHA1); + + CertificateCollection collection; + collection.load(lOCSPCertificates); + RUNNER_ASSERT(collection.sort()); + CertificateList sorted = collection.getChain(); + + ocsp.setTrustedStore(sorted); + VerificationStatusSet status = ocsp.validateCertificateList(sorted); + + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_CONNECTION_FAILED), + "Caught OCSP connection error - check if " + "wrt-tests-vcore-ocsp-server.sh is running!"); + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_GOOD), + "Caught OCSP verification error exception"); + RUNNER_ASSERT_MSG(status.contains(VERIFICATION_STATUS_REVOKED), + "Caught OCSP verification error exception"); + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_UNKNOWN), + "Caught OCSP verification error exception"); + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_VERIFICATION_ERROR), + "Caught OCSP verification error exception"); + + CertificateCacheDAO::clearCertificateCache(); +} + +RUNNER_TEST(test73_ocsp_local_validation_error_unknown_cert) +{ + CertificateCacheDAO::clearCertificateCache(); + + CertificateList lOCSPCertificates; + CertificatePtr certificatePtr; + CertificatePtr pCert0; + CertificatePtr pCert1; + CertificatePtr pRootCert; + std::string caRootPath(cert_store_path + "cacert.pem"), + certLevel0Path(cert_store_path + "1second_level.pem"), + certLevel1Path(cert_store_path + "1third_level.pem"); + + pRootCert = RevocationCheckerBase::loadPEMFile(caRootPath.c_str()); + if (!pRootCert) { + RUNNER_ASSERT_MSG(false, "Couldn't load cacerr.pem"); + } + lOCSPCertificates.push_back(pRootCert); + + pCert0 = RevocationCheckerBase::loadPEMFile(certLevel0Path.c_str()); + if (!pCert0) { + RUNNER_ASSERT_MSG(false, "Couldn't load 1second_level.pem"); + } + lOCSPCertificates.push_back(CertificatePtr(pCert0)); + + pCert1 = RevocationCheckerBase::loadPEMFile(certLevel1Path.c_str()); + if (!pCert1) { + RUNNER_ASSERT_MSG(false, "Couldn't load 1third_level.pem"); + } + lOCSPCertificates.push_back(CertificatePtr(pCert1)); + + OCSP ocsp; + ocsp.setDigestAlgorithmForCertId(ValidationCore::OCSP::SHA1); + ocsp.setDigestAlgorithmForRequest(ValidationCore::OCSP::SHA1); + + CertificateCollection collection; + collection.load(lOCSPCertificates); + RUNNER_ASSERT(collection.sort()); + CertificateList sorted = collection.getChain(); + + ocsp.setTrustedStore(sorted); + VerificationStatusSet status = ocsp.validateCertificateList(sorted); + + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_CONNECTION_FAILED), + "Caught OCSP connection error - check if " + "wrt-tests-vcore-ocsp-server.sh is running!"); + RUNNER_ASSERT_MSG(status.contains(VERIFICATION_STATUS_GOOD), + "Caught OCSP verification error exception"); + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_REVOKED), + "Caught OCSP verification error exception"); + RUNNER_ASSERT_MSG(status.contains(VERIFICATION_STATUS_VERIFICATION_ERROR), + "Caught OCSP verification error exception"); + RUNNER_ASSERT_MSG(!status.contains(VERIFICATION_STATUS_UNKNOWN), + "Caught OCSP verification error exception"); + + CertificateCacheDAO::clearCertificateCache(); +} + diff --git a/tests/vcore/TestEnv.cpp b/tests/vcore/TestEnv.cpp new file mode 100644 index 0000000..b12c3e1 --- /dev/null +++ b/tests/vcore/TestEnv.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011 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. + */ +#include +#include +#include + +#include + +#include "TestEnv.h" + +const char *storePath = "code-signing_wac"; + +int addCertToStore(const char* name){ + int result = cert_svc_add_certificate_to_store(name, storePath); + + if (CERT_SVC_ERR_NO_ERROR != result) { + LogError("Error adding certificate: " << name << " To: " << storePath); + } + return result; +} + +//long int removeCertFromStore(const char* subjectName, const char* issuerName) +//{ +// long int result = OPERATION_SUCCESS; +// /* Retrieve all the certificates from store */ +// certmgr_cert_id certId; +// certmgr_mem_buff certRetrieved; +// certmgr_ctx context; +// char storeId[CERTMGR_MAX_PLUGIN_ID_SIZE]; +// char type[CERTMGR_MAX_CERT_TYPE_SIZE]; +// unsigned char certBuff[CERTMGR_MAX_BUFFER_SIZE * 2]; +// +// certmgr_cert_descriptor descriptor; +// certId.storeId = storeId; +// certId.type = type; +// +// CERTMGR_INIT_CONTEXT((&context), (sizeof(certmgr_ctx))) +// std::string storeName("Operator"); +// strncpy(context.storeId, storeName.c_str(), storeName.size()); +// +// certRetrieved.data = certBuff; +// certRetrieved.size = CERTMGR_MAX_BUFFER_SIZE * 2; +// +// certRetrieved.firstFree = 0; +// +// for(certRetrieved.firstFree = 0; +// OPERATION_SUCCESS == +// (result = certmgr_retrieve_certificate_from_store( &context, &certRetrieved, &certId)); +// certRetrieved.firstFree = 0) +// { +// if(OPERATION_SUCCESS == +// certmgr_extract_certificate_data(&certRetrieved, &descriptor)){ +// LogDebug("The subject of this certificate is " << descriptor.mandatory.subject); +// LogDebug("The issuer of this certificate is " << descriptor.mandatory.issuer); +// } +// +// if(strcmp(descriptor.mandatory.subject, subjectName) == 0 && +// strcmp(descriptor.mandatory.issuer,issuerName) == 0 && +// OPERATION_SUCCESS == certmgr_remove_certificate_from_store(&certId)) +// { +// LogDebug("***Certificate has been REMOVED***"); +// return OPERATION_SUCCESS; +// } +// } +// +// if(ERR_NO_MORE_CERTIFICATES == result){ +// LogDebug("***THIS CERT IS NOT IN STORE***"); +// return OPERATION_SUCCESS; +// } +// +// return result; +//} + +int removeCertGivenByFilename(const char* name){ + int result = cert_svc_delete_certificate_from_store(name, storePath); + + if (CERT_SVC_ERR_NO_ERROR != result) { + LogError("Error removing certificate: " << name << " From: " << storePath); + } + + return result; +} + diff --git a/tests/vcore/TestEnv.h b/tests/vcore/TestEnv.h new file mode 100644 index 0000000..88c5d3a --- /dev/null +++ b/tests/vcore/TestEnv.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 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. + */ +#ifndef _TESTENV_H_ +#define _TESTENV_H_ + +int addCertToStore(const char *name); +long int removeCertFromStore(const char *subjectName, const char *issuerName); +int removeCertGivenByFilename(const char *name); + +#endif diff --git a/tests/vcore/cert-svc-tests-vcore-ocsp-server.sh b/tests/vcore/cert-svc-tests-vcore-ocsp-server.sh new file mode 100644 index 0000000..3a9a5ac --- /dev/null +++ b/tests/vcore/cert-svc-tests-vcore-ocsp-server.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# Copyright (c) 2011 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. +# + +pkill -9 openssl # if previously it was launched and openssl didn't close sockets + +OPENSSL_CONF=/opt/apps/widget/tests/vcore_certs/openssl.cnf openssl ocsp -nrequest 5 -index /opt/apps/widget/tests/vcore_certs/demoCA/index.txt -port 8881 -rsigner /opt/apps/widget/tests/vcore_certs/respcert.pem -rkey /opt/apps/widget/tests/vcore_certs/respcert.key -CA /opt/apps/widget/tests/vcore_certs/demoCA/cacert.pem + +echo "--- OCSP server shutdown..." diff --git a/tests/vcore/certificate-generator/.gitignore b/tests/vcore/certificate-generator/.gitignore new file mode 100644 index 0000000..96be371 --- /dev/null +++ b/tests/vcore/certificate-generator/.gitignore @@ -0,0 +1,28 @@ +1second_level.csr +1second_level.key +1second_level.pem +1third_level.key +1third_level.pem +1third_level.request +2second_level.csr +2second_level.key +2second_level.pem +2third_level.key +2third_level.pem +2third_level.request +3second_level.csr +3second_level.key +3second_level.pem +3third_level.key +3third_level.pem +3third_level.request +cacrl1.pem +cacrl2.pem +demoCA/index.txt +demoCA/index.txt.attr +demoCA/index.txt.attr.old +demoCA/index.txt.old +demoCA/newcerts/ +respcert.csr +respcert.key +respcert.pem diff --git a/tests/vcore/certificate-generator/create_certs.sh b/tests/vcore/certificate-generator/create_certs.sh new file mode 100755 index 0000000..4d03927 --- /dev/null +++ b/tests/vcore/certificate-generator/create_certs.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# Copyright (c) 2011 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. +# + +#Prerequisite to run script is to +#create root certificate and directory structure (demoCA) with command: +#/usr/lib/ssl/misc/CA.sh -newca +#for automated tests default structure is created in demoCA.init + +#make sure current dir has no files from previous generation +rm -r 1* 2* 3* ca* respcert* demoCA +cp -R demoCA.init demoCA +echo "01" > ./demoCA/crlnumber + +for index in 1 2 3 +do + #create certificate A + openssl genrsa -out ${index}second_level.key 1024 -passin pass:1234 -config ./openssl.cnf + openssl req -new -key ${index}second_level.key -out ${index}second_level.csr -passin pass:1234 -config ./openssl.cnf < +#include +#include +#include +#include +#include +#include +#include + +FileInputMapping::FileInputMapping(const std::string &fileName) + : m_handle(-1), + m_size(0), + m_address(NULL) +{ + // Open device and map it to user space + int file = TEMP_FAILURE_RETRY(open(fileName.c_str(), O_RDONLY)); + + if (file == -1) + { + int error = errno; + ThrowMsg(FileInputMapping::Exception::OpenFailed, + "Failed to open file. errno = " << error); + } + + // Scoped close on file + DPL::ScopedClose scopedClose(file); + + // Calculate file size + off64_t size = lseek64(file, 0, SEEK_END); + + if (size == static_cast(-1)) + { + int error = errno; + ThrowMsg(FileInputMapping::Exception::OpenFailed, + "Failed to seek file. errno = " << error); + } + + // Map file to usespace + void *address = mmap(0, static_cast(size), + PROT_READ, MAP_SHARED, file, 0); + + if (address == MAP_FAILED) + { + int error = errno; + ThrowMsg(FileInputMapping::Exception::OpenFailed, + "Failed to map file. errno = " << error); + } + + // Release scoped close + m_handle = scopedClose.Release(); + + // Save mapped up address + m_size = size; + m_address = static_cast(address); + + LogPedantic("Created file mapping: " << fileName << + " of size: " << m_size << + " at address: " << std::hex << static_cast(m_address)); +} + +FileInputMapping::~FileInputMapping() +{ + // Close mapping + if (munmap(m_address, static_cast(m_size)) == -1) + { + int error = errno; + LogPedantic("Failed to munmap file. errno = " << error); + } + + // Close file descriptor + if (TEMP_FAILURE_RETRY(close(m_handle)) == -1) + { + int error = errno; + LogPedantic("Failed to close file. errno = " << error); + } +} + +off64_t FileInputMapping::GetSize() const +{ + return m_size; +} + +const unsigned char *FileInputMapping::GetAddress() const +{ + return m_address; +} diff --git a/tests/vcore/file_input_mapping.h b/tests/vcore/file_input_mapping.h new file mode 100644 index 0000000..c4a19b6 --- /dev/null +++ b/tests/vcore/file_input_mapping.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011 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 file_input_mapping.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of file input mapping + */ +#ifndef DPL_FILE_INPUT_MAPPING_H +#define DPL_FILE_INPUT_MAPPING_H + +#include +#include + +class FileInputMapping + : private DPL::Noncopyable +{ +public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, OpenFailed) + }; + +private: + int m_handle; + off64_t m_size; + unsigned char *m_address; + +public: + /** + * Constructor + */ + explicit FileInputMapping(const std::string &fileName); + + /** + * Destructor + */ + ~FileInputMapping(); + + /** + * Get file mapping total size + * + * @return 64-bit size + */ + off64_t GetSize() const; + + /** + * Get file mapping base address + * + * @return Base address of file mapping + */ + const unsigned char *GetAddress() const; +}; + +#endif // DPL_FILE_INPUT_MAPPING_H diff --git a/tests/vcore/test-cases/keys/CAbundle.crt b/tests/vcore/test-cases/keys/CAbundle.crt new file mode 100644 index 0000000..4edaeda --- /dev/null +++ b/tests/vcore/test-cases/keys/CAbundle.crt @@ -0,0 +1,3677 @@ +-----BEGIN CERTIFICATE----- +MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx +EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h +bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy +YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp +Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4MDBaFw0xMTExMzAy +MzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsG +A1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3Jt +YWNhbyAtIElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYD +VQQDEyhBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVA +isamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma/3pUpgcfNAj0vYm5gsyj +Qo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt4CyNrY50 +QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYt +bRhFboUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbUR +yEeNvZneVRKAAU6ouwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwID +AQABo4HSMIHPME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0 +cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYwPQYDVR0f +BDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFj +cmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1 +U/hgIh6OcgLAfiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGl +YjJe+9zd+izPRbBqXPVQA34EXcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75Fos +SzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQfS//JYeIc7Fue2JNLd00UOSMMaiK/ +t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0u +mlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPb +K+9A46sd33oqK8n8 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 +IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB +IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA +Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO +BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi +MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ +ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ +8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 +zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y +fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 +w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc +G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k +epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q +laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ +QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU +fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 +YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w +ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY +gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe +MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 +IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy +dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw +czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 +dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl +aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC +AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg +b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB +ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc +nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg +18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c +gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl +Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY +sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T +SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF +CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum +GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk +zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW +omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGCDCCA/CgAwIBAgIBATANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 +IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB +IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA +Y2FjZXJ0Lm9yZzAeFw0wNTEwMTQwNzM2NTVaFw0zMzAzMjgwNzM2NTVaMFQxFDAS +BgNVBAoTC0NBY2VydCBJbmMuMR4wHAYDVQQLExVodHRwOi8vd3d3LkNBY2VydC5v +cmcxHDAaBgNVBAMTE0NBY2VydCBDbGFzcyAzIFJvb3QwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCrSTURSHzSJn5TlM9Dqd0o10Iqi/OHeBlYfA+e2ol9 +4fvrcpANdKGWZKufoCSZc9riVXbHF3v1BKxGuMO+f2SNEGwk82GcwPKQ+lHm9WkB +Y8MPVuJKQs/iRIwlKKjFeQl9RrmK8+nzNCkIReQcn8uUBByBqBSzmGXEQ+xOgo0J +0b2qW42S0OzekMV/CsLj6+YxWl50PpczWejDAz1gM7/30W9HxM3uYoNSbi4ImqTZ +FRiRpoWSR7CuSOtttyHshRpocjWr//AQXcD0lKdq1TuSfkyQBX6TwSyLpI5idBVx +bgtxA+qvFTia1NIFcm+M+SvrWnIl+TlG43IbPgTDZCciECqKT1inA62+tC4T7V2q +SNfVfdQqe1z6RgRQ5MwOQluM7dvyz/yWk+DbETZUYjQ4jwxgmzuXVjit89Jbi6Bb +6k6WuHzX1aCGcEDTkSm3ojyt9Yy7zxqSiuQ0e8DYbF/pCsLDpyCaWt8sXVJcukfV +m+8kKHA4IC/VfynAskEDaJLM4JzMl0tF7zoQCqtwOpiVcK01seqFK6QcgCExqa5g +eoAmSAC4AcCTY1UikTxW56/bOiXzjzFU6iaLgVn5odFTEcV7nQP2dBHgbbEsPyyG +kZlxmqZ3izRg0RS0LKydr4wQ05/EavhvE/xzWfdmQnQeiuP43NJvmJzLR5iVQAX7 +6QIDAQABo4G/MIG8MA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUHAQEEUTBPMCMG +CCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggrBgEFBQcwAoYc +aHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBBMD8GCCsGAQQB +gZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9yZy9pbmRleC5w +aHA/aWQ9MTAwDQYJKoZIhvcNAQEEBQADggIBAH8IiKHaGlBJ2on7oQhy84r3HsQ6 +tHlbIDCxRd7CXdNlafHCXVRUPIVfuXtCkcKZ/RtRm6tGpaEQU55tiKxzbiwzpvD0 +nuB1wT6IRanhZkP+VlrRekF490DaSjrxC1uluxYG5sLnk7mFTZdPsR44Q4Dvmw2M +77inYACHV30eRBzLI++bPJmdr7UpHEV5FpZNJ23xHGzDwlVks7wU4vOkHx4y/CcV +Bc/dLq4+gmF78CEQGPZE6lM5+dzQmiDgxrvgu1pPxJnIB721vaLbLmINQjRBvP+L +ivVRIqqIMADisNS8vmW61QNXeZvo3MhN+FDtkaVSKKKs+zZYPumUK5FQhxvWXtaM +zPcPEAxSTtAWYeXlCmy/F8dyRlecmPVsYGN6b165Ti/Iubm7aoW8mA3t+T6XhDSU +rgCvoeXnkm5OvfPi2RSLXNLrAWygF6UtEOucekq9ve7O/e0iQKtwOIj1CodqwqsF +YMlIBdpTwd5Ed2qz8zw87YC8pjhKKSRf/lk7myV6VmMAZLldpGJ9VzZPrYPvH5JT +oI53V93lYRE9IwCQTDz6o2CTBKOvNfYOao9PSmCnhQVsRqGP9Md246FZV/dxssRu +FFxtbUFm3xuTsdQAw+7Lzzw9IYCpX2Nl/N3gX6T0K/CFcUHUZyX7GrGXrtaZghNB +0m6lG5kngOcLqagA +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIESzCCAzOgAwIBAgIJAJigUTEEXRQpMA0GCSqGSIb3DQEBBQUAMHYxCzAJBgNV +BAYTAkRFMQ8wDQYDVQQIEwZIZXNzZW4xDjAMBgNVBAcTBUZ1bGRhMRAwDgYDVQQK +EwdEZWJjb25mMRMwEQYDVQQDEwpEZWJjb25mIENBMR8wHQYJKoZIhvcNAQkBFhBq +b2VyZ0BkZWJpYW4ub3JnMB4XDTA1MTEwNTE3NTUxNFoXDTE1MTEwMzE3NTUxNFow +djELMAkGA1UEBhMCREUxDzANBgNVBAgTBkhlc3NlbjEOMAwGA1UEBxMFRnVsZGEx +EDAOBgNVBAoTB0RlYmNvbmYxEzARBgNVBAMTCkRlYmNvbmYgQ0ExHzAdBgkqhkiG +9w0BCQEWEGpvZXJnQGRlYmlhbi5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCvbOo0SrIwI5IMlsshH8WF3dHB9r9JlSKhMPaybawa1EyvZspMQ3wa +F5qxNf3Sj+NElEmjseEqvCZiIIzqwerHu0Qw62cDYCdCd2+Wb5m0bPYB5CGHiyU1 +eNP0je42O0YeXG2BvUujN8AviocVo39X2YwNQ0ryy4OaqYgm2pRlbtT2ESbF+SfV +Y2iqQj/f8ymF+lHo/pz8tbAqxWcqaSiHFAVQJrdqtFhtoodoNiE3q76zJoUkZTXB +k60Yc3MJSnatZCpnsSBr/D7zpntl0THrUjjtdRWCjQVhqfhM1yZJV+ApbLdheFh0 +ZWlSxdnp25p0q0XYw/7G92ELyFDfBUUNAgMBAAGjgdswgdgwHQYDVR0OBBYEFMuV +dFNb4mCWUFbcP5LOtxFLrEVTMIGoBgNVHSMEgaAwgZ2AFMuVdFNb4mCWUFbcP5LO +txFLrEVToXqkeDB2MQswCQYDVQQGEwJERTEPMA0GA1UECBMGSGVzc2VuMQ4wDAYD +VQQHEwVGdWxkYTEQMA4GA1UEChMHRGViY29uZjETMBEGA1UEAxMKRGViY29uZiBD +QTEfMB0GCSqGSIb3DQEJARYQam9lcmdAZGViaWFuLm9yZ4IJAJigUTEEXRQpMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGZXxHg4mnkvilRIM1EQfGdY +S5b/WcyF2MYSTeTvK4aIB6VHwpZoZCnDGj2m2D3CkHT0upAD9o0zM1tdsfncLzV+ +mDT/jNmBtYo4QXx5vEPwvEIcgrWjwk7SyaEUhZjtolTkHB7ACl0oD0r71St4iEPR +qTUCEXk2E47bg1Fz58wNt/yo2+4iqiRjg1XCH4evkQuhpW+dTZnDyFNqwSYZapOE +TBA+9zBb6xD1KM2DdY7r4GiyYItN0BKLfuWbh9LXGbl1C+f4P11g+m2MPiavIeCe +1iazG5pcS3KoTLACsYlEX24TINtg4kcuS81XdllcnsV3Kdts0nIqPj6uhTTZD0k= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDvjCCA3ygAwIBAgIFJQaThoEwCwYHKoZIzjgEAwUAMIGFMQswCQYDVQQGEwJG +UjEPMA0GA1UECBMGRnJhbmNlMQ4wDAYDVQQHEwVQYXJpczEQMA4GA1UEChMHUE0v +U0dETjEOMAwGA1UECxMFRENTU0kxDjAMBgNVBAMTBUlHQy9BMSMwIQYJKoZIhvcN +AQkBFhRpZ2NhQHNnZG4ucG0uZ291di5mcjAeFw0wMjEyMTMxNDM5MTVaFw0yMDEw +MTcxNDM5MTRaMIGFMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGRnJhbmNlMQ4wDAYD +VQQHEwVQYXJpczEQMA4GA1UEChMHUE0vU0dETjEOMAwGA1UECxMFRENTU0kxDjAM +BgNVBAMTBUlHQy9BMSMwIQYJKoZIhvcNAQkBFhRpZ2NhQHNnZG4ucG0uZ291di5m +cjCCAbYwggErBgcqhkjOOAQBMIIBHgKBgQCFkMImdk9zDzJfTO4XPdAAmLbAdWws +ZiEMZh19RyTo3CyhFqO77OIXrwY6vc1pcc3MgWJ0dgQpAgrDMtmFFxpUu4gmjVsx +8GpxQC+4VOgLY8Cvmcd/UDzYg07EIRto8BwCpPJ/JfUxwzV2V3N713aAX+cEoKZ/ +s+kgxC6nZCA7oQIVALME/JYjkdW2uKIGngsEPbXAjdhDAoGADh/uqWJx94UBm31c +9d8ZTBfRGRnmSSRVFDgPWgA69JD4BR5da8tKz+1HjfMhDXljbMH86ixpD5Ka1Z0V +pRYUPbyAoB37tsmXMJY7kjyD19d5VdaZboUjVvhH6UJy5lpNNNGSvFl4fqkxyvw+ +pq1QV0N5RcvK120hlXdfHUX+YKYDgYQAAoGAQGr7IuKJcYIvJRMjxwl43KxXY2xC +aoCiM/bv117MfI94aNf1UusGhp7CbYAY9CXuL60P0oPMAajbaTE5Z34AuITeHq3Y +CNMHwxalip8BHqSSGmGiQsXeK7T+r1rPXsccZ1c5ikGDZ4xn5gUaCyy2rCmb+fOJ +6VAfCbAbAjmNKwejdzB1MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgFGMBUG +A1UdIAQOMAwwCgYIKoF6AXkBAQEwHQYDVR0OBBYEFPkeNRcUf8idzpKblYbLNxs0 +MQhSMB8GA1UdIwQYMBaAFPkeNRcUf8idzpKblYbLNxs0MQhSMAsGByqGSM44BAMF +AAMvADAsAhRVh+CJA5eVyEYU5AO9Tm7GxX0rmQIUBCqsU5u1WxoZ5lEXicDX5/Ob +sRQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYT +AkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQ +TS9TR0ROMQ4wDAYDVQQLEwVEQ1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG +9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMB4XDTAyMTIxMzE0MjkyM1oXDTIw +MTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAM +BgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NTSTEO +MAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2 +LmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaI +s9z4iPf930Pfeo2aSVz2TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2 +xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCWSo7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4 +u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYyHF2fYPepraX/z9E0+X1b +F8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNdfrGoRpAx +Vs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGd +PDPQtQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNV +HSAEDjAMMAoGCCqBegF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAx +NjAfBgNVHSMEGDAWgBSjBS8YYFDCiQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUF +AAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RKq89toB9RlPhJy3Q2FLwV3duJ +L92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3QMZsyK10XZZOY +YLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg +Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2a +NjSaTFR+FwNIlQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R +0982gaEbeC9xs/FZTEYYKKuF0mBWWg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEFBQAw +gYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2FzaGluZ3Rv +bjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFCQS5FQ09NIFJv +b3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3RydXN0LmNvbTAeFw05 +OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQswCQYDVQQGEwJVUzELMAkG +A1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24xFzAVBgNVBAoTDkFCQS5FQ09N +LCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBSb290IENBMSQwIgYJKoZIhvcNAQkB +FhVhZG1pbkBkaWdzaWd0cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCx0xHgeVVDBwhMywVCAOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM +0KLMsFWWU4RmBQDaREmA2FQKpSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFG +PR7wuSw0X4x8TAgpnUBV6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGU +LOR4SCQaJRk665WcOQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZs +iSrK2jMTecJVjO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU ++/94Qby9cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYB +Af8CAQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k +qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvTZOir +vRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHegTYjHInYZ +w8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm/lowdiT/QHI8 +eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgxfexgeqMiKL0ZJGA/ +O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJTzFxiNmIf1Q= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx +HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh +IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAwMFoXDTM3MTEyMDE1 +MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg +SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M +IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U +0pPlLYnKhHw/EEMbjIt8hFj4JHxIzyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItI +TuLCxFlpMGK2MKKMCxGZYTVtfu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAf +RC+iYkGzuxgh28pxPIzstrkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqF +zQ6axOAAsNUl6twr5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqh +BC4aMqiaILGcLCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEA +AaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jY +PXy+XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/ +BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNMeUWn +9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7CegCgTXT +Ct8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77BfWgDrvq2g+EQF +Z7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oTLW4jYYehY0KswsuX +n2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCzvhGbRWeDhhmH05i9CBoW +H1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmwX7A5KGgOc90lmt4S +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx +HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh +IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAwMFoXDTM3MDkyODIz +NDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg +SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M +IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ +7ouZzU9AhqS2TcnZsdw8TQ2FTBVsRotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilb +m2BPJoPRYxJWSXakFsKlnUWsi4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOY +xFSMFkpBd4aVdQxHAWZg/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZ +YYCLqJV+FNwSbKTQ2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbq +JS5Gr42whTg0ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fx +I2rSAG2X+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETz +kxmlJ85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh +EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNoKk/S +Btc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJKg71ZDIM +gtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1ExMVCgyhwn2RAu +rda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaAFE9pbQN+nZ8HGEO8txBO +1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAO/Ouyugu +h4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0cnAxa8cZmIDJgt43d15Ui47y6mdP +yXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRFASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q +7C+qPBR7V8F+GBRn7iTGvboVsNIYvbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKT +RuidDV29rs4prWPVVRaAMCf/drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ +ClTluUI8JPu3B5wwn3la5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyB +M5kYJRF3p+v9WAksmWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQ +my8YJPamTQr5O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xO +AU++CrYD062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT +9Y41xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H +hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOLZ8/5 +fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs +IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 +MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h +bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v +dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt +H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 +uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX +mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX +a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN +E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 +WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD +VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 +Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU +cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx +IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN +AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH +YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC +Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX +c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a +mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw +MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD +VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul +CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n +tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl +dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch +PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC ++Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O +BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl +MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk +ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X +7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz +43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY +eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl +pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA +WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx +MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB +ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV +BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV +6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX +GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP +dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH +1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF +62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW +BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL +MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU +cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv +b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6 +IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/ +iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao +GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh +4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm +XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 +MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK +EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh +BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq +xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G +87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i +2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U +WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 +0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G +A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr +pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL +ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm +aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv +hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm +hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 +P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y +iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no +xqE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP +bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2 +MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft +ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk +hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym +1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW +OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb +2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko +O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU +AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF +Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb +LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir +oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C +MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds +sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP +bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2 +MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft +ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC +206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci +KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2 +JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9 +BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e +Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B +PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67 +Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq +Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ +o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3 ++L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj +YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj +FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn +xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2 +LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc +obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8 +CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe +IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA +DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F +AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX +Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb +AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl +Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw +RY8mkaKO/qk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn +MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL +ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg +b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa +MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB +ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw +IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B +AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb +unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d +BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq +7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 +0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX +roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG +A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j +aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p +26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA +BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud +EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN +BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB +AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd +p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi +1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc +XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 +eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu +tGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn +MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL +ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo +YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 +MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy +NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G +A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA +A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 +Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s +QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV +eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 +B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh +z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T +AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i +ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w +TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH +MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD +VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE +VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B +AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM +bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi +ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG +VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c +ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ +AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw +PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz +cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 +MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz +IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ +ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR +VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL +kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd +EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas +H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 +HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud +DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 +QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu +Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ +AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 +yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR +FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA +ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB +kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM +MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD +QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM +MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD +QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E +jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo +ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI +ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu +Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg +AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 +HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA +uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa +TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg +xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q +CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x +O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs +6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp +ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow +fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV +BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM +cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S +HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 +CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk +3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz +6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV +HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud +EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv +Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw +Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww +DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 +5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj +Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI +gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ +aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl +izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 +aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla +MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO +BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD +VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW +fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt +TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL +fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW +1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 +kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G +A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v +ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo +dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu +Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ +HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 +pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS +jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ +xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn +dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx +ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w +MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD +VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx +FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu +ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7 +gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH +fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a +ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT +ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk +c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto +dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt +aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI +hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk +QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/ +h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq +nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR +rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2 +9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQDHbanJEMTiye/hXQWJM8TDANBgkqhkiG9w0BAQUFADBf +MQswCQYDVQQGEwJOTDESMBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdp +Tm90YXIgUm9vdCBDQTEgMB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmww +HhcNMDcwNTE2MTcxOTM2WhcNMjUwMzMxMTgxOTIxWjBfMQswCQYDVQQGEwJOTDES +MBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdpTm90YXIgUm9vdCBDQTEg +MB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmwwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCssFjBAL3YIQgLK5r+blYwBZ8bd5AQQVzDDYcRd46B +8cp86Yxq7Th0Nbva3/m7wAk3tJZzgX0zGpg595NvlX89ubF1h7pRSOiLcD6VBMXY +tsMW2YiwsYcdcNqGtA8Ui3rPENF0NqISe3eGSnnme98CEWilToauNFibJBN4ViIl +HgGLS1Fx+4LMWZZpiFpoU8W5DQI3y0u8ZkqQfioLBQftFl9VkHXYRskbg+IIvvEj +zJkd1ioPgyAVWCeCLvriIsJJsbkBgWqdbZ1Ad2h2TiEqbYRAhU52mXyC8/O3AlnU +JgEbjt+tUwbRrhjd4rI6y9eIOI6sWym5GdOY+RgDz0iChmYLG2kPyes4iHomGgVM +ktck1JbyrFIto0fVUvY//s6EBnCmqj6i8rZWNBhXouSBbefK8GrTx5FrAoNBfBXv +a5pkXuPQPOWx63tdhvvL5ndJzaNl3Pe5nLjkC1+Tz8wwGjIczhxjlaX56uF0i57p +K6kwe6AYHw4YC+VbqdPRbB4HZ4+RS6mKvNJmqpMBiLKR+jFc1abBUggJzQpjotMi +puih2TkGl/VujQKQjBR7P4DNG5y6xFhyI6+2Vp/GekIzKQc/gsnmHwUNzUwoNovT +yD4cxojvXu6JZOkd69qJfjKmadHdzIif0dDJZiHcBmfFlHqabWJMfczgZICynkeO +owIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUiGi/4I41xDs4a2L3KDuEgcgM100wDQYJKoZIhvcNAQEFBQADggIBADsC +jcs8MOhuoK3yc7NfniUTBAXT9uOLuwt5zlPe5JbF0a9zvNXD0EBVfEB/zRtfCdXy +fJ9oHbtdzno5wozWmHvFg1Wo1X1AyuAe94leY12hE8JdiraKfADzI8PthV9xdvBo +Y6pFITlIYXg23PFDk9Qlx/KAZeFTAnVR/Ho67zerhChXDNjU1JlWbOOi/lmEtDHo +M/hklJRRl6s5xUvt2t2AC298KQ3EjopyDedTFLJgQT2EkTFoPSdE2+Xe9PpjRchM +Ppj1P0G6Tss3DbpmmPHdy59c91Q2gmssvBNhl0L4eLvMyKKfyvBovWsdst+Nbwed +2o5nx0ceyrm/KkKRt2NTZvFCo+H0Wk1Ya7XkpDOtXHAd3ODy63MUkZoDweoAZbwH +/M8SESIsrqC9OuCiKthZ6SnTGDWkrBFfGbW1G/8iSlzGeuQX7yCpp/Q/rYqnmgQl +nQ7KN+ZQ/YxCKQSa7LnPS3K94gg2ryMvYuXKAdNw23yCIywWMQzGNgeQerEfZ1jE +O1hZibCMjFCz2IbLaKPECudpSyDOwR5WS5WpI2jYMNjD67BVUc3l/Su49bsRn1NU +9jQZjHkJNsphFyUXC4KYcwx3dMPVDceoEkzHp1RxRy4sGn3J4ys7SN4nhKdjNrN9 +j6BkOSQNPXuHr2ZcdBtLc7LljPCGmbjlxd+Ewbfr +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV +UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL +EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ +BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x +ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg +bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ +j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV +Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG +SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx +JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI +RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw +MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5 +fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i ++DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG +SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN +QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+ +gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGpMQsw +CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp +dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE +CxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0B +CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDExODE4NTVaFw0wODExMjgx +ODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO +U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0 +IENvLjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx +ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdf +WvnTLnUv2Chi0ZMv/E3Uq4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uK +xBmd9LIO/BZsubEFkoPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBE +zUNKcI5YhZXhTizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F +5X5yP4WdlGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMv +OnNn7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG +9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+Legz +ZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvVWlHG4VME +lo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX8ngvYzZAOONG +Dx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn86Oawde3uPclwx12q +gUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsTF7ANUkz+/m9c4pFuHf2k +Ytdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV +UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL +EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ +BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x +ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/ +k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso +LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o +TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG +SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx +JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI +RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3 +MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C +TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5 +WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG +SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR +xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL +B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGpMQsw +CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp +dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE +CxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0B +CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAyMjQ2MTZaFw0wODExMjcy +MjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO +U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0 +IENvLjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx +ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbV +p9oaBBg5kkp4o4HC9Xd6ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWw +BZoPFflrWXJW8vo5/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl +5WJp3OXuAFK9MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi +3sOP17ihYqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+ +QVCvbK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG +9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWogWxyQ +2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6HE3K1GjN +I3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV6YyDfFk/xPEL +553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8PzGn0EdzMzkbzE5q +10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30sPDst2yC7S8xmUJMqbIN +uBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NBX0NQUyBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAyMDAw +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVu +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAyMDcxNjE2NDBaFw0yMDAy +MDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7Ny +Spj10InJrWPNTTVRaoTUrcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0 +iJBeAZfv6lOm3fzB3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn +5JVn1j+SgF7yNH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHd +BgNVHR8EgdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0 +MUAwPgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy +ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0Lm5l +dCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAy +MDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQDAgEGMB8GA1UdIwQY +MBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQWBBSEi3T9xY3A/ydtIDdF +fP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4w +AwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWAO9GK9Q6nIMstZVXQkvTnhLUGJoMS +hAusO7JE7r3PQNsgDrpuFOow4DtifH+La3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/ +GpsKkMWr2tGzhtQvJFJcem3G8v7lTRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKd +zmVml64mXg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UEChML +RW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xfQ1BTIGlu +Y29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg +RW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJl +IFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAyMDQxNzIwMDBa +Fw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDE/MD0GA1UE +CxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p +dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVk +MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp +b24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO +8GCGD9JYf9Mzly0XonUwtZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaB +bL3+qPZ1V1eMkGxKwz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2 +dWcTC5/oVzbIXQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4 +QgEBBAQDAgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoT +C0VudHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAyMDAw +IEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0IFNlY3Vy +ZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEw +KwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIwNDE3NTAwMFowCwYD +VR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc/vuLkpyw8m4iMB0GA1Ud +DgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNVHRMEBTADAQH/MB0GCSqGSIb2 +fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBi24GRzsia +d0Iv7L0no1MPUBvqTpLwqa+poLpIYcvvyQbvH9X07t9WLebKahlzqlO+krNQAraF +JnJj2HVQYnUUt7NQGj/KEQALhUVpbbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1U +yrrJzOCE98g+EZfTYAkYvAX/bIkz8OwVDw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy +MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA +vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G +CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA +WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo +oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ +h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18 +f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN +B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy +vUxFnmG6v4SBkgPR0ml8xQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UEBhMC +VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50cnVzdC5u +ZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBsaW1pdHMgbGlh +Yi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBaMIHJMQswCQYDVQQGEwJVUzEU +MBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9D +bGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMq +RW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0G +CSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo +6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux +5zDeg7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zm +AqTmT173iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSC +ARkwggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50 +cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5m +by9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMp +IDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQg +Q2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCyg +KqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9DbGllbnQxLmNybDArBgNV +HRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkxMDEyMTkyNDMwWjALBgNVHQ8E +BAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW/O5bs8qZdIuV6kwwHQYDVR0OBBYE +FMT7nCl7l81MlvzuW7PKmXSLlepMMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA +BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7 +pFuPeJoSSJn59DXeDDYHAmsQOokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzz +wy5E97BnRqqS5TvaHBkUODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/a +EkP/TOYGJqibGapEPHayXOw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC +VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u +ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc +KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u +ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1 +MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE +ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j +b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF +bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg +U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA +A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/ +I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3 +wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC +AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb +oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 +BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p +dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk +MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp +b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu +dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0 +MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi +E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa +MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI +hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN +95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd +2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV +UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy +dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 +MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx +dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f +BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A +cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC +AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw +ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj +IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF +MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA +A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y +7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh +1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT +ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw +MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj +dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l +c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC +UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc +58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/ +o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr +aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA +A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA +Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv +8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT +ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw +MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j +LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ +KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo +RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu +WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw +Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD +AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK +eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM +zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+ +WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN +/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj +dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0 +NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD +VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G +vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/ +BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C +AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX +MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl +IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw +NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq +y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF +MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA +A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy +0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1 +E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMx +IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1 +dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w +HhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTELMAkGA1UEBhMCRVMx +IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1 +dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5u +Cp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5Vj1H5WuretXDE7aTt/6MNbg9kUDGvASdY +rv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJHlShbz++AbOCQl4oBPB3z +hxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf3H5idPay +BQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcL +iam8NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcb +AgMBAAGjgZ8wgZwwKgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lv +bmFsLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0 +MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E +FgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQADggEBAEdz/o0n +VPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq +u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36m +hoEyIwOdyPdfwUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzfl +ZKG+TQyTmAyX9odtsz/ny4Cm7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBp +QWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YGVM+h4k0460tQtcsm9MracEpqoeJ5 +quGnM/b9Sh/22WA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD +VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv +bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv +b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV +UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU +cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds +b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH +iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS +r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 +04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r +GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 +3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P +lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgwFgYD +VQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRydXN0IFJv +b3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQswCQYDVQQGEwJV +UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQDExNHVEUgQ3liZXJU +cnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyv +RLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4M +ypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/5 +1KiOQswkwB6RJ0q1bQaAYznEol44AwIDAQABMA0GCSqGSIb3DQEBBAUAA4GBABKz +dcZfHeFhVYAA1IFLezEPI2PnPfMD+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWl +IjeaY8JIILTbcuPI9tl8vrGvU9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9Apy +bW1EDp3zdHSo1TRJ6V6e6bR64eVaH4QwnNOfpSXY +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs +IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg +R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A +PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8 +Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL +TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL +5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7 +S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe +2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap +EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td +EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv +/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN +A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0 +abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF +I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz +4iIprn2DQKi6bA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx +MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 +AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA +ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 +7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W +kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI +mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ +KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 +6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl +4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K +oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj +UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU +AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy +c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 +IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV +VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 +cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT +QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh +F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v +c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w +mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd +VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX +teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ +f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe +Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ +nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY +MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG +9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX +IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn +ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z +uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN +Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja +QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW +koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 +ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt +DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm +bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy +c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD +VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 +c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 +WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG +FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq +XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL +se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb +KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd +IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 +y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt +hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc +QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 +Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV +HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ +KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ +L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr +Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo +ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY +T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz +GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m +1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV +OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH +6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX +QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYTAkVT +MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE +ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE +ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEuMCwGA1UECxMl +SVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl +SVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3 +DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAwNTkzOFoXDTI1MTIyNzAw +NTkzOFowggESMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYD +VQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5n +IFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4g +IEItNjA5Mjk0NTIxLjAsBgNVBAsTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxLjAsBgNVBAMTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4FEnpwvdr9G5Q1uCN0VWcu+atsIS7ywS +zHb5BlmvXSHU0lq4oNTzav3KaY1mSPd05u42veiWkXWmcSjK5yISMmmwPh5r9FBS +YmL9Yzt9fuzuOOpi9GyocY3h6YvJP8a1zZRCb92CRTzo3wno7wpVqVZHYUxJZHMQ +KD/Kvwn/xi8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBTrsxl588GlHKzcuh9morKb +adB4CDCCAUQGA1UdIwSCATswggE3gBTrsxl588GlHKzcuh9morKbadB4CKGCARqk +ggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UE +BxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBT +ZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBC +LTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xBU0UxIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UxIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYD +VR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggr +BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIB +FQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhC +AQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB +D2lwc0BtYWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UxIENBIENlcnRp +ZmljYXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC +BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQtFito +dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEuY3JsMD8GCWCG +SAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25D +TEFTRTEuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93d3cuaXBzLmVzL2lw +czIwMDIvcmVuZXdhbENMQVNFMS5odG1sPzA6BglghkgBhvhCAQgELRYraHR0cDov +L3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFTRTEuaHRtbDBzBgNVHR8EbDBq +MDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEu +Y3JsMDWgM6Axhi9odHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAy +Q0xBU0UxLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9v +Y3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEAK9Dr/drIyllq2tPMMi7JVBuK +Yn4VLenZMdMu9Ccj/1urxUq2ckCuU3T0vAW0xtnIyXf7t/k0f3gA+Nak5FI/LEpj +V4F1Wo7ojPsCwJTGKbqz3Bzosq/SLmJbGqmODszFV0VRFOlOHIilkfSj945RyKm+ +hjM+5i9Ibq9UkE6tsSU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYTAkVT +MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE +ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE +ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEuMCwGA1UECxMl +SVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl +SVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3 +DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAxMDE0NFoXDTI1MTIyNzAx +MDE0NFowggESMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYD +VQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5n +IFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4g +IEItNjA5Mjk0NTIxLjAsBgNVBAsTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxLjAsBgNVBAMTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxf+DrDGaBtT8FK+n/ra+osTBLsBjzLZ +H49NzjaY2uQARIwo2BNEKqRrThckQpzTiKRBgtYj+4vJhuW5qYIF3PHeH+AMmVWY +8jjsbJ0gA8DvqqPGZARRLXgNo9KoOtYkTOmWehisEyMiG3zoMRGzXwmqMHBxRiVr +SXGAK5UBsh8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBS4k/8uy9wsjqLnev42USGj +mFsMNDCCAUQGA1UdIwSCATswggE3gBS4k/8uy9wsjqLnev42USGjmFsMNKGCARqk +ggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UE +BxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBT +ZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBC +LTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xBU0UzIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UzIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYD +VR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggr +BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIB +FQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhC +AQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB +D2lwc0BtYWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UzIENBIENlcnRp +ZmljYXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC +BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQtFito +dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMuY3JsMD8GCWCG +SAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25D +TEFTRTMuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93d3cuaXBzLmVzL2lw +czIwMDIvcmVuZXdhbENMQVNFMy5odG1sPzA6BglghkgBhvhCAQgELRYraHR0cDov +L3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFTRTMuaHRtbDBzBgNVHR8EbDBq +MDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMu +Y3JsMDWgM6Axhi9odHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAy +Q0xBU0UzLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9v +Y3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEAF2VcmZVDAyevJuXr0LMXI/dD +qsfwfewPxqmurpYPdikc4gYtfibFPPqhwYHOU7BC0ZdXGhd+pFFhxu7pXu8Fuuu9 +D6eSb9ijBmgpjnn1/7/5p6/ksc7C0YBCJwUENPjDfxZ4IwwHJPJGR607VNCv1TGy +r33I6unUVtkOE7LFRVA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYTAkVT +MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE +ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE +ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMm +SVBTIENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT +JklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI +hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcNMDExMjI5MDEwNTMyWhcNMjUxMjI3 +MDEwNTMyWjCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ +BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp +bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G +LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMw +gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALsw19zQVL01Tp/FTILq0VA8R5j8 +m2mdd81u4D/u6zJfX5/S0HnllXNEITLgCtud186Nq1KLK3jgm1t99P1tCeWu4Wwd +ByOgF9H5fahGRpEiqLJpxq339fWUoTCUvQDMRH/uxJ7JweaPCjbB/SQ9AaD1e+J8 +eGZDi09Z8pvZ+kmzAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUZyaW56G/2LUDnf47 +3P7yiuYV3TAwggFGBgNVHSMEggE9MIIBOYAUZyaW56G/2LUDnf473P7yiuYV3TCh +ggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ +BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp +bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G +LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOC +AQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUF +BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYB +BAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglg +hkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1Ud +EgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMSBD +QSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG +SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgBhvhC +AQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMS5j +cmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmV2 +b2NhdGlvbkNMQVNFQTEuaHRtbD8wPQYJYIZIAYb4QgEHBDAWLmh0dHA6Ly93d3cu +aXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTEuaHRtbD8wOwYJYIZIAYb4QgEI +BC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5Q0xBU0VBMS5odG1s +MHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvaXBz +MjAwMkNMQVNFQTEuY3JsMDagNKAyhjBodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBz +MjAwMi9pcHMyMDAyQ0xBU0VBMS5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF +BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAH66iqyA +AIQVCtWYUQxkxZwCWINmyq0eB81+atqAB98DNEock8RLWCA1NnHtogo1EqWmZaeF +aQoO42Hu6r4okzPV7Oi+xNtff6j5YzHIa5biKcJboOeXNp13XjFr/tOn2yrb25aL +H2betgPAK7N41lUH5Y85UN4HI3LmvSAUS7SG +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYTAkVT +MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE +ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE +ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMm +SVBTIENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT +JklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI +hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcNMDExMjI5MDEwNzUwWhcNMjUxMjI3 +MDEwNzUwWjCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ +BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp +bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G +LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMw +gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAO6AAPYaZC6tasiDsYun7o/ZttvN +G7uGBiJ2MwwSbUhWYdLcgiViL5/SaTBlA0IjWLxH3GvWdV0XPOH/8lhneaDBgbHU +VqLyjRGZ/fZ98cfEXgIqmuJKtROKAP2Md4bm15T1IHUuDky/dMQ/gT6DtKM4Ninn +6Cr1jIhBqoCm42zvAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUHp9XUEe2YZM50yz8 +2l09BXW3mQIwggFGBgNVHSMEggE9MIIBOYAUHp9XUEe2YZM50yz82l09BXW3mQKh +ggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ +BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp +bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G +LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOC +AQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUF +BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYB +BAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglg +hkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1Ud +EgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMyBD +QSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG +SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgBhvhC +AQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMy5j +cmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmV2 +b2NhdGlvbkNMQVNFQTMuaHRtbD8wPQYJYIZIAYb4QgEHBDAWLmh0dHA6Ly93d3cu +aXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTMuaHRtbD8wOwYJYIZIAYb4QgEI +BC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5Q0xBU0VBMy5odG1s +MHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvaXBz +MjAwMkNMQVNFQTMuY3JsMDagNKAyhjBodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBz +MjAwMi9pcHMyMDAyQ0xBU0VBMy5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF +BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAEo9IEca +2on0eisxeewBwMwB9dbB/MjD81ACUZBYKp/nNQlbMAqBACVHr9QPDp5gJqiVp4MI +3y2s6Q73nMify5NF8bpqxmdRSmlPa/59Cy9SKcJQrSRE7SOzSMtEQMEDlQwKeAYS +AfWRMS1Jjbs/RU4s4OjNtckUFQzjB4ObJnXv +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARwxCzAJBgNVBAYTAkVT +MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE +ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE +ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEzMDEGA1UECxMq +SVBTIENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTMwMQYD +VQQDEypJUFMgQ0EgQ2hhaW5lZCBDQXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +HjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczAeFw0wMTEyMjkwMDUzNTha +Fw0yNTEyMjcwMDUzNThaMIIBHDELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNl +bG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQg +cHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMu +ZXMgQy5JLkYuICBCLTYwOTI5NDUyMTMwMQYDVQQLEypJUFMgQ0EgQ2hhaW5lZCBD +QXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMzAxBgNVBAMTKklQUyBDQSBDaGFp +bmVkIENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYP +aXBzQG1haWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcVpJJ +spQgvJhPUOtopKdJC7/SMejHT8KGC/po/UNaivNgkjWZOLtNA1IhW/A3mTXhQSCB +hYEFcYGdtJUZqV92NC5jNzVXjrQfQj8VXOF6wV8TGDIxya2+o8eDZh65nAQTy2nB +Bt4wBrszo7Uf8I9vzv+W6FS+ZoCua9tBhDaiPQIDAQABo4IEQzCCBD8wHQYDVR0O +BBYEFKGtMbH5PuEXpsirNPxShwkeYlJBMIIBTgYDVR0jBIIBRTCCAUGAFKGtMbH5 +PuEXpsirNPxShwkeYlJBoYIBJKSCASAwggEcMQswCQYDVQQGEwJFUzESMBAGA1UE +CBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJ +bnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0Bt +YWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxMzAxBgNVBAsTKklQUyBDQSBD +aGFpbmVkIENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEzMDEGA1UEAxMqSVBT +IENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI +hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8E +BQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMG +CCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYB +BAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMw +EYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5lczBC +BglghkgBhvhCAQ0ENRYzQ2hhaW5lZCBDQSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkg +aHR0cDovL3d3dy5pcHMuZXMvMCkGCWCGSAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlw +cy5lcy9pcHMyMDAyLzA3BglghkgBhvhCAQQEKhYoaHR0cDovL3d3dy5pcHMuZXMv +aXBzMjAwMi9pcHMyMDAyQ0FDLmNybDA8BglghkgBhvhCAQMELxYtaHR0cDovL3d3 +dy5pcHMuZXMvaXBzMjAwMi9yZXZvY2F0aW9uQ0FDLmh0bWw/MDkGCWCGSAGG+EIB +BwQsFipodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3JlbmV3YWxDQUMuaHRtbD8w +NwYJYIZIAYb4QgEIBCoWKGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5 +Q0FDLmh0bWwwbQYDVR0fBGYwZDAuoCygKoYoaHR0cDovL3d3dy5pcHMuZXMvaXBz +MjAwMi9pcHMyMDAyQ0FDLmNybDAyoDCgLoYsaHR0cDovL3d3d2JhY2suaXBzLmVz +L2lwczIwMDIvaXBzMjAwMkNBQy5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF +BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAERyMJ1W +WKJBGyi3leGmGpVfp3hAK+/blkr8THFj2XOVvQLiogbHvpcqk4A0hgP63Ng9HgfN +HnNDJGD1HWHc3JagvPsd4+cSACczAsDAK1M92GsDgaPb1pOVIO/Tln4mkImcJpvN +b2ar7QMiRDjMWb2f2/YHogF/JsRj9SVCXmK9 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICtzCCAiACAQAwDQYJKoZIhvcNAQEEBQAwgaMxCzAJBgNVBAYTAkVTMRIwEAYD +VQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UEChMQSVBT +IFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcwFQYDVQQD +Ew5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVz +MB4XDTk4MDEwMTIzMjEwN1oXDTA5MTIyOTIzMjEwN1owgaMxCzAJBgNVBAYTAkVT +MRIwEAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UE +ChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcw +FQYDVQQDEw5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwu +aXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyY +XZhkJAk8IbPMGbWOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1 +gf/+rHhwLWjhOgeYlQJU3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4 +Nu+z4cYgjui0OLzhPvYR3oydAQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACzzw3lY +JN7GO9HgQmm47mSzPWIBubOE3yN93ZjPEKn+ANgilgUTB1RXxafey9m4iEL2mdsU +dx+2/iU94aI+A6mB0i1sR/WWRowiq8jMDQ6XXotBtDvECgZAHd1G9AHduoIuPD14 +cJ58GNCr+Lh3B0Zx8coLY1xq+XKU1QFPoNtC +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIIODCCB6GgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCAR4xCzAJBgNVBAYTAkVT +MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE +ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE +ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjE0MDIGA1UECxMr +SVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTE0MDIG +A1UEAxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAxMTAx +OFoXDTI1MTIyNzAxMTAxOFowggEeMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFy +Y2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5l +dCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlw +cy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxNDAyBgNVBAsTK0lQUyBDQSBUaW1lc3Rh +bXBpbmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxNDAyBgNVBAMTK0lQUyBDQSBU +aW1lc3RhbXBpbmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0B +CQEWD2lwc0BtYWlsLmlwcy5lczCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +vLjuVqWajOY2ycJioGaBjRrVetJznw6EZLqVtJCneK/K/lRhW86yIFcBrkSSQxA4 +Efdo/BdApWgnMjvEp+ZCccWZ73b/K5Uk9UmSGGjKALWkWi9uy9YbLA1UZ2t6KaFY +q6JaANZbuxjC3/YeE1Z2m6Vo4pjOxgOKNNtMg0GmqaMCAwEAAaOCBIAwggR8MB0G +A1UdDgQWBBSL0BBQCYHynQnVDmB4AyKiP8jKZjCCAVAGA1UdIwSCAUcwggFDgBSL +0BBQCYHynQnVDmB4AyKiP8jKZqGCASakggEiMIIBHjELMAkGA1UEBhMCRVMxEjAQ +BgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJ +UFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJp +cHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMTQwMgYDVQQLEytJUFMg +Q0EgVGltZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTQwMgYDVQQD +EytJUFMgQ0EgVGltZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4w +HAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAM +BgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYB +BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIB +FgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYD +VR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlw +cy5lczBHBglghkgBhvhCAQ0EOhY4VGltZXN0YW1waW5nIENBIENlcnRpZmljYXRl +IGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgECBBwWGmh0 +dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMEAGCWCGSAGG+EIBBAQzFjFodHRwOi8v +d3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBpbmcuY3JsMEUGCWCG +SAGG+EIBAwQ4FjZodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25U +aW1lc3RhbXBpbmcuaHRtbD8wQgYJYIZIAYb4QgEHBDUWM2h0dHA6Ly93d3cuaXBz +LmVzL2lwczIwMDIvcmVuZXdhbFRpbWVzdGFtcGluZy5odG1sPzBABglghkgBhvhC +AQgEMxYxaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lUaW1lc3RhbXBp +bmcuaHRtbDB/BgNVHR8EeDB2MDegNaAzhjFodHRwOi8vd3d3Lmlwcy5lcy9pcHMy +MDAyL2lwczIwMDJUaW1lc3RhbXBpbmcuY3JsMDugOaA3hjVodHRwOi8vd3d3YmFj +ay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyVGltZXN0YW1waW5nLmNybDAvBggrBgEF +BQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZI +hvcNAQEFBQADgYEAZbrBzAAalZHK6Ww6vzoeFAh8+4Pua2JR0zORtWB5fgTYXXk3 +6MNbsMRnLWhasl8OCvrNPzpFoeo2zyYepxEoxZSPhExTCMWTs/zif/WN87GphV+I +3pGW7hdbrqXqcGV4LCFkAZXOzkw+UPS2Wctjjba9GNSHSl/c7+lW8AoM6HU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx +ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 +b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD +EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05 +OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G +A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh +Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l +dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG +SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK +gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX +iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc +Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E +BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G +SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu +b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh +bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv +Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln +aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0 +IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh +c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph +biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo +ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP +UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj +YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo +dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA +bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06 +sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa +n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS +NitjrFgBazMpUIaD8QFI +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx +ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 +b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD +EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X +DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw +DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u +c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr +TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA +OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC +2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW +RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P +AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW +ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0 +YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz +b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO +ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB +IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs +b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs +ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s +YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg +a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g +SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0 +aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg +YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg +Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY +ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g +pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4 +Fp1hBWeAyNDYpQcCNJgEjTME1A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV +MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe +TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0 +dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB +KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0 +N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC +dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu +MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL +b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD +zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi +3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8 +WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY +Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi +NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC +ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4 +QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0 +YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz +aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu +IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm +ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg +ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs +amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv +IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3 +Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6 +ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1 +YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg +dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs +b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G +CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO +xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP +0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ +QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk +f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK +8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx +ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 +b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD +EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz +aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w +MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G +A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh +Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l +dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh +bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq +eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe +r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5 +3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd +vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l +mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC +wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg +hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0 +TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh +biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg +ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg +dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6 +b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl +c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0 +ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3 +dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu +ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh +bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo +ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3 +Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u +ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA +A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ +MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+ +NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR +VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY +83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3 +macqaJVmlaut74nLYKkGEsaUR+ko +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi +MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV +UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO +ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz +c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP +OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl +mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF +BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 +qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw +gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu +bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp +dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 +6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ +h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH +/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN +pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz +MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw +IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR +dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp +li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D +rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ +WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug +F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU +xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC +Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv +dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw +ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl +IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh +c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy +ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI +KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T +KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq +y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p +dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD +VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk +fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 +7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R +cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y +mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW +xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK +SnQ2+Q== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz +BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y +aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG +9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy +NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y +azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw +Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl +cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD +cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs +2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY +JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE +Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ +n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A +PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUFADA6 +MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp +dHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAxNDlaMDoxGTAX +BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAx +MDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDV3f5mCc8kPD6ugU5O +isRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dYrIMKo1W1exeQFYRMiu4mmdxY +78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYtbzZUaMjShFbuklNhCbM/OZuoyZu9 +zp9+1BlqFikYvtc6adwlWzMaUQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAd +BgNVHQ4EFgQUxMAcpAeU/c1NAdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEA +Py1q4yZDlX2Jl2X7deRyHUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdN +T1+nr6JGFLkM88y9am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgD +mMrzVcydro7BqkWY+o8aoI2II/EVQQ2lRj6RP4vr93E= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6 +MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp +dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX +BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy +MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp +eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg +/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl +wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh +AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2 +PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu +AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR +MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc +HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/ +Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ +f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO +rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch +6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3 +7CAFYd4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY +MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t +dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 +WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD +VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 +9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ +DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 +Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N +QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ +xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G +A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG +kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr +Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU +JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot +RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP +MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx +MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV +BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG +29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk +oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk +3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL +qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN +nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw +DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX +ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H +DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO +TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv +kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w +zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP +MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx +MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV +BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o +Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt +5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s +3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej +vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu +8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw +DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil +zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ +3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD +FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 +Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 +ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO +TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy +MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk +ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn +ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71 +9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO +hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U +tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o +BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh +SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww +OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv +cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA +7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k +/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm +eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6 +u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy +7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR +iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW +MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg +Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 +MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi +U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh +cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk +pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf +OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C +Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT +Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi +HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM +Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w ++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ +Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 +Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B +26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID +AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j +ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js +LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM +BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 +Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy +dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh +cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh +YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg +dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp +bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ +YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT +TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ +9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 +jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW +FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz +ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 +ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L +EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu +L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq +yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC +O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V +um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh +NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFFjCCBH+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBsDELMAkGA1UEBhMCSUwx +DzANBgNVBAgTBklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0 +Q29tIEx0ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBG +cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +YWRtaW5Ac3RhcnRjb20ub3JnMB4XDTA1MDMxNzE3Mzc0OFoXDTM1MDMxMDE3Mzc0 +OFowgbAxCzAJBgNVBAYTAklMMQ8wDQYDVQQIEwZJc3JhZWwxDjAMBgNVBAcTBUVp +bGF0MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMRowGAYDVQQLExFDQSBBdXRob3Jp +dHkgRGVwLjEpMCcGA1UEAxMgRnJlZSBTU0wgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkxITAfBgkqhkiG9w0BCQEWEmFkbWluQHN0YXJ0Y29tLm9yZzCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEA7YRgACOeyEpRKSfeOqE5tWmrCbIvNP1h3D3TsM+x +18LEwrHkllbEvqoUDufMOlDIOmKdw6OsWXuO7lUaHEe+o5c5s7XvIywI6Nivcy+5 +yYPo7QAPyHWlLzRMGOh2iCNJitu27Wjaw7ViKUylS7eYtAkUEKD4/mJ2IhULpNYI +LzUCAwEAAaOCAjwwggI4MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0G +A1UdDgQWBBQcicOWzL3+MtUNjIExtpidjShkjTCB3QYDVR0jBIHVMIHSgBQcicOW +zL3+MtUNjIExtpidjShkjaGBtqSBszCBsDELMAkGA1UEBhMCSUwxDzANBgNVBAgT +BklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4x +GjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBGcmVlIFNTTCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSYWRtaW5Ac3Rh +cnRjb20ub3JnggEAMB0GA1UdEQQWMBSBEmFkbWluQHN0YXJ0Y29tLm9yZzAdBgNV +HRIEFjAUgRJhZG1pbkBzdGFydGNvbS5vcmcwEQYJYIZIAYb4QgEBBAQDAgAHMC8G +CWCGSAGG+EIBDQQiFiBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAy +BglghkgBhvhCAQQEJRYjaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL2NhLWNybC5j +cmwwKAYJYIZIAYb4QgECBBsWGWh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy8wOQYJ +YIZIAYb4QgEIBCwWKmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9pbmRleC5waHA/ +YXBwPTExMTANBgkqhkiG9w0BAQQFAAOBgQBscSXhnjSRIe/bbL0BCFaPiNhBOlP1 +ct8nV0t2hPdopP7rPwl+KLhX6h/BquL/lp9JmeaylXOWxkjHXo0Hclb4g4+fd68p +00UOpO6wNnQt8M2YI3s3S9r+UZjEHjQ8iP2ZO1CnwYszx8JSFhKVU2Ui77qLzmLb +cCOxgN8aIDjnfg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln +biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF +MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT +d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 +76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ +bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c +6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE +emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd +MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt +MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y +MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y +FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi +aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM +gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB +qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 +lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn +8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 +45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO +UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 +O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC +bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv +GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a +77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC +hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 +92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp +Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w +ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt +Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu +IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw +WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD +ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y +IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn +IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+ +6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob +jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw +izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl ++zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY +zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP +pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF +KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW +ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB +AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0 +ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW +IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA +A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0 +uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+ +FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7 +jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/ +u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D +YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1 +puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa +icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG +DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x +kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z +Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk +MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 +YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg +Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT +AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp +Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9 +m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih +FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/ +TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F +EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco +kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu +HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF +vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo +19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC +L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW +bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX +JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw +FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j +BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc +K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf +ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik +Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB +sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e +3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR +ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip +mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH +b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf +rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms +hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y +zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6 +MBr1mmz0DlP5OlvRHA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF +MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU +QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI +MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMSkwJwYJKoZIhvcN +AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla +Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy +ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y +IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1 +c3RDZW50ZXIgQ2xhc3MgMiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA +dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0y +AClxgwENv4wB3NrGrTmkqYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDw +TFXlay3HhQswHJJOgtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8 +/vhYnvgpjbB7zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3 +LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G +CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+WLDO/ +jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xRT3h2oNms +Gb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/AcASZ4smZHcFFk +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF +MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU +QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI +MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENBMSkwJwYJKoZIhvcN +AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla +Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy +ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y +IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1 +c3RDZW50ZXIgQ2xhc3MgMyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA +dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUF +Lg2N7KBAahwOJ6ZQkmtQGwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGw +Dtf7pBc9r6tpepYnv68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDW +w1Krj10nnGvAo+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3 +LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G +CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4iJIE +Tb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yCGdHHsbHD +2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQSCdS7kjXvD9s0 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE +SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg +Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV +BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl +cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA +vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu +Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a +0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1 +4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN +eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD +R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG +A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu +dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME +Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3 +WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw +HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ +KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO +Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX +wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ +2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89 +9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0 +jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38 +aQNiuJkFBT1reBK9sG9l +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE +SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw +ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU +REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr +2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s +2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU +GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj +dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r +TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB +AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv +c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl +ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu +MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg +T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud +HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD +VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny +bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy +MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ +J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG +SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom +JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO +inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y +caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB +mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ +YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9 +BKNDLdr8C2LqL19iUw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOc +UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx +c8SxMQswCQYDVQQGDAJUUjEPMA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykg +MjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8 +dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMxMDI3MTdaFw0xNTAz +MjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2Vy +dGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYD +VQQHDAZBTktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kg +xLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEu +xZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7 +XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GXyGl8hMW0kWxsE2qkVa2k +heiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8iSi9BB35J +YbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5C +urKZ8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1 +JuTm5Rh8i27fbMx4W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51 +b0dewQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV +9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46sWrv7/hg0Uw2ZkUd82YCdAR7 +kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxEq8Sn5RTOPEFh +fEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy +B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdA +aLX/7KfS0zgYnNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKS +RGQDJereW26fyfJOrN3H +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOc +UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx +c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xS +S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg +SGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3 +WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVrdHJv +bmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJU +UjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSw +bGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe +LiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnef +J1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdh +R3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJ +Qv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGX +JHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p +zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58S +Fq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq +ECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 +Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFz +gw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotH +uFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LS +y3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5UrbnBEI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/ +MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow +PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR +IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q +gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy +yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts +F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2 +jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx +ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC +VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK +YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH +EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN +Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud +DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE +MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK +UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf +qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK +ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE +JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7 +hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1 +EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm +nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX +udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz +ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe +LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl +pYYsfPQS +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD +VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT +ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj +IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X +DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw +EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE +ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy +dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD +QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53 +dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK +wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7 +G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF +AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7 +c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P +9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD +VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT +ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt +YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu +Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT +AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa +MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp +b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG +cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh +d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY +DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E +rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq +uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN +BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP +MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa +/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei +gQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD +VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT +ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p +dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv +bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa +QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY +BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u +IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl +bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu +Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs +Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI +Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD +ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG +SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH +b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh +KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD +VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy +dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t +MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB +MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG +A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp +b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl +cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv +bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE +VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ +ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR +uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG +9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI +hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM +pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD +VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm +MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx +MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3 +dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl +cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3 +DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD +gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91 +yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX +L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj +EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG +7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e +QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ +qdq5snUb9kLy78fyGPmJvKP/iiMucEc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMCWkEx +FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN +BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAd +BgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcwMTAxMDAwMDAwWhcN +MjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4g +Q2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsG +A1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1l +c3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYrWHhhRYZT +6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQa +Wt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL +8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC +9RAIDb/LogWK0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQ +pgCed/r8zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZ +CayJSdM= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB +ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt +TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1 +NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 +IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD +VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS +Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2 +N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH +iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe +YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1 +axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g +yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD +AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh +ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V +VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB +BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y +IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs +QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4 +ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM +YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb +QErNaLly7HF27FSOH4UMAWr6pjisH8SE +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB +kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw +IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG +EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD +VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu +dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 +E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ +D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK +4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq +lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW +bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB +o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT +MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js +LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr +BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB +AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj +j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH +KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv +2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 +mfnGV/TJVTl4uix5yaaIK/QI +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB +rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt +Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa +Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV +BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l +dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE +AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B +YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9 +hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l +L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm +SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM +1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws +6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw +Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50 +aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH +AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u +7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0 +xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ +rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim +eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk +USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB +lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt +SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG +A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe +MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v +d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh +cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn +0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ +M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a +MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd +oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI +DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy +oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 +dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy +bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF +BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli +CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE +CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t +3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS +KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz +BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y +aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG +9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy +NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y +azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw +Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl +cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y +LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+ +TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y +TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0 +LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW +I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw +nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz +BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y +aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG +9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy +NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y +azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw +Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl +cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY +dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 +WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS +v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v +UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu +IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC +W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh +c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 +NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD +VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp +bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N +H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR +4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN +BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo +EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5 +FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx +lA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh +c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy +MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp +emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X +DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg +UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo +YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 +MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK +VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm +Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID +AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J +h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul +uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68 +DzFc6PLZ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 +nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO +8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV +ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb +PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 +6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr +n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a +qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 +wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 +ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs +pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 +E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz +cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 +MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV +BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN +ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh +YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7 +FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G +CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg +J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc +r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns +YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y +aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe +Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj +IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx +KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM +HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw +DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC +AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji +nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX +rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn +jBJ7xUS0rg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy +aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp +Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV +BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp +Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g +Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU +J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO +JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY +wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o +koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN +qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E +Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe +xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u +7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU +sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI +sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP +cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz +cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 +MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV +BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN +ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE +BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is +I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G +CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do +lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc +AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh +c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy +MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp +emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X +DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg +UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo +YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 +MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 +pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 +13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID +AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk +U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i +F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY +oJ2daZH9 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b +N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t +KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu +kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm +CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ +Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu +imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te +2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe +DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p +F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt +TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh +c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy +MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp +emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X +DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg +UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo +YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 +MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM +HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK +qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID +AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj +cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y +cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP +T8qAkbYp +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1 +GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ ++mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd +U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm +NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY +ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ +ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1 +CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq +g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm +fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c +2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/ +bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG +A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD +VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0 +MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV +BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy +dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ +ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII +0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI +uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI +hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3 +YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc +1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUFADCB +wTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTwwOgYDVQQL +EzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1 +dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1OTU5WjCBpTEXMBUGA1UEChMO +VmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsx +OzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5j +b20vcnBhIChjKTAwMSwwKgYDVQQDEyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1 +dGhvcml0eSBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVli +zrQJIkRpivglWtvtDbc2fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU +/OB4naCTuQk9I1F/RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11 +S7zi6ESHzeZBCiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/ +AgEAMEUGA1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0 +dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0 +cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIGCCsG +AQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j +b20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2DcIBcBlK0lRW +HqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQnKeg3S/LvRJdrF1Ea +w1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937ntag+RaypJXUie28/sJyU +58dzq6wf7iWbwBbtt8pb8BQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx +DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2 +aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcNMDAwODE2MjI1 +MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT +QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp +b24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZDK9vZBv42pWUJGkzEXDK41Z0ohdX +ZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJXLB1LRckaeNCYOTudNargFbYiCjh+20i +/SN8RnNPflRzHqgsVVh1t0zzWkWlAhr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU +58fy+pmjIlC++QU3o63tmsPm7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/g +halMCXI5Etuz9c9OYmTaxhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E +1w0cslSsMoW0ZA3eQbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ +ca3CBfYDdYDOqU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHb +mQdpNSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ +kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoLaxhN +dBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/RtLdh6yumJ +ivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8ofyrEK9ca3Cn +B+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr +MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl +cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw +CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h +dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l +cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h +2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E +lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV +ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq +299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t +vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL +dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF +AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR +zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 +LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd +7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw +++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx +IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs +cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v +dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0 +MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl +bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD +DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r +WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU +Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs +HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj +z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf +SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl +AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG +KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P +AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j +BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC +VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX +ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB +ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd +/ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB +A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn +k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9 +iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv +2G0xffX8oRAHh84vWdw+WNs= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMC +VVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9v +dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDAxMDExMTY0MTI4WhcNMjEwMTE0 +MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSww +KgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0G +A1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n13 +5zHCLielTWi5MbqNQ1mXx3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHE +SxP9cMIlrCL1dQu3U+SlK93OvRw6esP3E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4O +JgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5OEL8pahbSCOz6+MlsoCu +ltQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4jsNtlAHCE +AQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMB +AAGjYTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcB +CzAyMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRw +b2xpY3kwDQYJKoZIhvcNAQEFBQADggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo +7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrvm+0fazbuSCUlFLZWohDo7qd/ +0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0ROhPs7fpvcmR7 +nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx +x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ +33ZwmVxwQ023tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQKEwli +ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEGA1UEAxMq +YmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0aW9uMB4XDTAy +MDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UEChMJYmVUUlVTVGVk +MRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAxBgNVBAMTKmJlVFJVU1Rl +ZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRhdGlvbjCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALx+xDmcjOPWHIb/ymKt4H8wRXqOGrO4x/nRNv8i +805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R9U+jK7wYFuK13XneIviCfsuBH/0nLI/6 +l2Qijvj/YaOcGx6Sj8CoCd8JEey3fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92B +FODEPM2dMPgwqZfT7syj0B9fHBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+Ymp +kbIq2eszh+6l/ePazIjmiSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7 +eHgZFLL8kFKJOGJgB7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIa +MA8GA1UdEwEB/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4A +AAEJKIORMTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3Ig +dXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu +dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJk +IHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmljYXRpb24g +UHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1l +bnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVTVGVkIHdlYiBzaXRl +LCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVjdHNfc2VydmljZXMvaW5k +ZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3dy5iZXRydXN0ZWQuY29tL3By +b2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwHQYDVR0OBBYEFEU9w6nR3D8kVpgc +cxiIav+DR+22MB8GA1UdIwQYMBaAFEU9w6nR3D8kVpgccxiIav+DR+22MA4GA1Ud +DwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCA +WXf82n+0S9/DZEtqTg6t8n1ZdwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu6 +7RMdmgduyzFiEuhjA6p9beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AY +gkHNZTfqjjJ+vWuZXTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb +4cV97yHgjQ5dUX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9 +CReJf8Py05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJX +VzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQgUm9vdCBD +QXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYyMDE0MjEwNFoX +DTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNVBAoTCWJlVFJVU1Rl +ZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRowGAYDVQQDExFiZVRSVVNU +ZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANS0c3oT +CjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4SP+00PpeQY1hRIfo7clY+vyTmt9P +6j41ffgzeubx181vSUs9Ty1uDoM6GHh3o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwM +jmVZxXH/YgmPqsWPzGCgc0rXOD8Vcr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX +2P8ZDoMbjNx4RWc0PfSvHI3kbWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2N +R47rtMNE5qdMf1ZD6Li8tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5j +rEq2I8QBoa2k5MUCAwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNV +HSAEggFQMIIBTDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQa +gfFSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1 +bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0 +ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9uIHBy +YWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJlVFJVU1Rl +ZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0L3Rl +cm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0 +L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYDVQQKEwliZVRSVVNUZWQx +CzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub2M3eKjEENGvKBxirZzAfBgNV +HSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxirZzAOBgNVHQ8BAf8EBAMCAf4wDQYJ +KoZIhvcNAQEFBQADggEBAHlh26Nebhax6nZR+csVm8tpvuaBa58oH2U+3RGFktTo +Qb9+M70j5/Egv6S0phkBxoyNNXxlpE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2 +jCBHOElQBp1yZzrwmAOtlmdE/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe +1lMBzW1MaFVA4e5rxyoAAEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5 +mlWXKWWuGVUlBXJH0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYc +tmBjRYoQtLpGEK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQKEwli +ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEGA1UEAxMq +YmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0aW9uMB4XDTAy +MDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UEChMJYmVUUlVTVGVk +MRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAxBgNVBAMTKmJlVFJVU1Rl +ZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRhdGlvbjCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1Q+xVkrYwfTVXDNvzDSduTPdQqJtO +K2/b9a0cS12zqcH+e0TrW6MFDR/FNCswACnxeECypP869AGIF37m1CbTukzqMvtD +d5eHI8XbQ6P1KqNRXuE70mVpflUVm3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdj +DheT389Lrm5zdeDzqrmkwAkbhepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCe +yv78IZTuEyhL11xeDGbu6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCkt +VjMFu5dZfsZJT4nXLySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMB +MIIBtwYDVR0gBIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYI +KwYBBQUHAgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRp +ZmljYXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug +b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0 +aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGljaCBjYW4gYmUg +Zm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0cHM6Ly93d3cuYmV0 +cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1sMEIGCCsGAQUF +BwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2Vz +L2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQDAgAHMIGJBgNVHR8EgYEwfzB9oHug +eaR3MHUxEjAQBgNVBAoTCWJlVFJVU1RlZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJv +b3QgQ0FzMTMwMQYDVQQDEypiZVRSVVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1w +bGVtZW50YXRpb24xDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEw +ODI0MjdagQ8yMDIyMDQxMTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaA +FH1w5a44iwY/qhwaj/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQw +qoSEFjAMBgNVHRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIE +kDANBgkqhkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ +5V04ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB +evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220Y/oz +ADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2KjiS2d2k +XgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFiaDrmLzfzgYYh +xKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep9w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUFADBi +MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENB +czEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVtZW50YXRp +b24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBiMRIwEAYDVQQKEwli +ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEvMC0GA1UEAxMm +YmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVtZW50YXRpb24wggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQwCY5X0LkGLG9uJIAiv11DpvpPrILn +HGhwhRujbrWqeNluB0s/6d/16uhUoWGKDi9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I +1DpAa5LxmZZk3tv/ePTulh1HiXzUvrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPk +tPDgaTuID0GQ+NRxQyTBjyZLO1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnU +GxlkVgoZ98zh/4avflherHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8er +cmsl9fNTGwxMLvF1S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIY +MIICFDAMBgNVHRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+ +AAADCSiDkTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5j +b20vcHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB +OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjcmVh +dGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRoZSB0aGVu +IGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdXNl +LCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1lbnQgYW5kIHRoZSBS +ZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IHRo +ZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93d3cuYmV0cnVzdGVkLmNvbS9w +cm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1sMAsGA1UdDwQEAwIBBjAfBgNVHSME +GDAWgBSp7BR++dlDzFMrFK3P9/BZiUHNGTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxSt +z/fwWYlBzRkwDQYJKoZIhvcNAQEFBQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g +6IHHtt9DwSwddUvUQo3neqh03GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuK +mET7m9cqg5c0Lcd9NUwtNLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbd +LrML3kqNWz2rDcI1UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28Bb +J1zTcwfBwvNMm2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3 +SK41ty8ymmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw +NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j +LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG +A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs +W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta +3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk +6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 +Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J +NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP +r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU +DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz +YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 +/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ +LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 +jVaMaA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIETzCCAzegAwIBAgIEO63vKTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE +ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg +U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDEwOTIzMTQxODE3WhcNMTEw +OTIzMTMxODE3WjB1MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v +LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWdu +ZXQgLSBDQSBLbGFzYSAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4SRW9Q58g5DY1Hw7h +gCRKBEdPdGn0MFHsfw7rlu/oQm7IChI/uWd9q5wwo77YojtTDjRnpgZsjqBeynX8T90vFILqsY2K +5CF1OESalwvVr3sZiQX79lisuFKat92u6hBFikFIVxfHHB67Af+g7u0dEHdDW7lwy81MwFYxBTRy +9wIDAQABo4IBbTCCAWkwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwggEEBgNVHSAE +gfwwgfkwgfYGDSsGAQQBvj8CAQoBAQAwgeQwgZoGCCsGAQUFBwICMIGNGoGKQ2VydHlmaWthdCB3 +eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVudGVtOiAiUG9saXR5a2EgQ2VydHlmaWthY2ppIGRs +YSBSb290Q0EiLiBDZXJ0eWZpa2F0IHd5c3Rhd2lvbnkgcHJ6ZXogUm9vdENBIHcgaGllcmFyY2hp +aSBDQyBTaWduZXQuMEUGCCsGAQUFBwIBFjlodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0b3Jp +dW0vZG9rdW1lbnR5L3BjX3Jvb3RjYS50eHQwHwYDVR0jBBgwFoAUwJvFIw0C4aZOSGsfAOnjmhQb +sa8wHQYDVR0OBBYEFMODHtVZd1T7TftXR/nEI1zR54njMA0GCSqGSIb3DQEBBQUAA4IBAQBRIHQB +FIGh8Jpxt87AgSLwIEEk4+oGy769u3NtoaR0R3WNMdmt7fXTi0tyTQ9V4AIszxVjhnUPaKnF1KYy +f8Tl+YTzk9ZfFkZ3kCdSaILZAOIrmqWNLPmjUQ5/JiMGho0e1YmWUcMci84+pIisTsytFzVP32/W ++sz2H4FQAvOIMmxB7EJX9AdbnXn9EXZ+4nCqi0ft5z96ZqOJJiCB3vSaoYg+wdkcvb6souMJzuc2 +uptXtR1Xf3ihlHaGW+hmnpcwFA6AoNrom6Vgzk6U1ienx0Cw28BhRSKqzKkyXkuK8gRflZUx84uf +tXncwKJrMiE3lvgOOBITRzcahirLer4c +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE9zCCA9+gAwIBAgIEPL/xoTANBgkqhkiG9w0BAQUFADB2MQswCQYDVQQGEwJQTDEfMB0GA1UE +ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg +U2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQgLSBQQ0EgS2xhc2EgMjAeFw0wMjA0MTkxMDI5NTNa +Fw0xNzA0MTgxMjUzMDdaMHUxCzAJBgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4g +eiBvLm8uMSQwIgYDVQQLExtDZW50cnVtIENlcnR5ZmlrYWNqaSBTaWduZXQxHzAdBgNVBAMTFkND +IFNpZ25ldCAtIENBIEtsYXNhIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqgLJu +QqY4yavbSgHg8CyfKTx4BokNSDOVz4eD9vptUr11Kqd06ED1hlH7Sg0goBFAfntNU/QTKwSBaNui +me7C4sSEdgsKrPoAhGb4Mq8y7Ty7RqZz7mkzNMqzL2L2U4yQ2QjvpH8MH0IBqOWEcpSkpwnrCDIm +RoTfd+YlZWKi2JceQixUUYIQ45Ox8+x8hHbvvZdgqtcvo8PW27qoHkp/7hMuJ44kDAGrmxffBXl/ +OBRZp0uO1CSLcMcVJzyr2phKhy406MYdWrtNPEluGs0GFDzd0nrIctiWAO4cmct4S72S9Q6e//0G +O9f3/Ca5Kb2I1xYLj/xE+HgjHX9aD2MhAgMBAAGjggGMMIIBiDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjCB4wYDVR0gBIHbMIHYMIHVBg0rBgEEAb4/AhQKAQEAMIHDMHUGCCsGAQUF +BwICMGkaZ0NlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 +eWthIENlcnR5ZmlrYWNqaSBQQ0EyIC0gQ2VydHlmaWthdHkgVXJ6ZWRvdyBLbGFzeSAyIi4wSgYI +KwYBBQUHAgEWPmh0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9kb2t1bWVudHkva2xh +c2EyL3BjX3BjYTIudHh0MD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly93d3cuc2lnbmV0LnBsL3Jl +cG96eXRvcml1bS9jcmwvcGNhMi5jcmwwHwYDVR0jBBgwFoAUwGxGyl2CfpYHRonE82AVXO08kMIw +HQYDVR0OBBYEFLtFBlILy4HNKVSzvHxBTM0HDowlMA0GCSqGSIb3DQEBBQUAA4IBAQBWTsCbqXrX +hBBev5v5cIuc6gJM8ww7oR0uMQRZoFSqvQUPWBYM2/TLI/f8UM9hSShUVj3zEsSj/vFHagUVmzuV +Xo5u0WK8iaqATSyEVBhADHrPG6wYcLKJlagge/ILA0m+SieyP2sjYD9MUB9KZIEyBKv0429UuDTw +6P7pslxMWJBSNyQxaLIs0SRKsqZZWkc7ZYAj2apSkBMX2Is1oHA+PwkF6jQMwCao/+CndXPUzfCF +6caa9WwW31W26MlXCvSmJgfiTPwGvm4PkPmOnmWZ3CczzhHl4q7ztHFzshJH3sZWDnrWwBFjzz5e +Pr3WHV1wA7EY6oT4zBx+2gT9XBTB +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEUzCCAzugAwIBAgIEPq+qjzANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJQTDE3MDUGA1UE +ChMuQ1ppQyBDZW50cmFzdCBTQSB3IGltaWVuaXUgTWluaXN0cmEgR29zcG9kYXJraTEZMBcGA1UE +AxMQQ1ppQyBDZW50cmFzdCBTQTAeFw0wMzA0MzAxMDUwNTVaFw0wODA0MjgxMDUwNTVaMGgxCzAJ +BgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4geiBvLm8uMR8wHQYDVQQDExZDQyBT +aWduZXQgLSBDQSBLbGFzYSAzMRcwFQYDVQQFEw5OdW1lciB3cGlzdTogNDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALVdeOM62cPH2NERFxbS5FIp/HSv3fgesdVsTUFxZbGtE+/E0RMl +KZQJHH9emx7vRYubsi4EOLCjYsCOTFvgGRIpZzx7R7T5c0Di5XFkRU4gjBl7aHJoKb5SLzGlWdoX +GsekVtl6keEACrizV2EafqjI8cnBWY7OxQ1ooLQp5AeFjXg+5PT0lO6TUZAubqjFbhVbxSWjqvdj +93RGfyYE76MnNn4c2xWySD07n7uno06TC0IJe6+3WSX1h+76VsIFouWBXOoM7cxxiLjoqdBVu24+ +P8e81SukE7qEvOwDPmk9ZJFtt1nBNg8a1kaixcljrA/43XwOPz6qnJ+cIj/xywECAwEAAaOCAQow +ggEGMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMDMGA1UdIAEB/wQpMCcwJQYEVR0g +ADAdMBsGCCsGAQUFBwIBFg93d3cuY2VudHJhc3QucGwwgY4GA1UdIwSBhjCBg4AU2a7r85Cp1iJN +W0Ca1LR6VG3996ShZaRjMGExCzAJBgNVBAYTAlBMMTcwNQYDVQQKEy5DWmlDIENlbnRyYXN0IFNB +IHcgaW1pZW5pdSBNaW5pc3RyYSBHb3Nwb2RhcmtpMRkwFwYDVQQDExBDWmlDIENlbnRyYXN0IFNB +ggQ9/0sQMB0GA1UdDgQWBBR7Y8wZkHq0zrY7nn1tFSdQ0PlJuTANBgkqhkiG9w0BAQUFAAOCAQEA +ldt/svO5c1MU08FKgrOXCGEbEPbQxhpM0xcd6Iv3dCo6qugEgjEs9Qm5CwUNKMnFsvR27cJWUvZb +MVcvwlwCwclOdwF6u/QRS8bC2HYErhYo9bp9yuxxzuow2A94c5fPqfVrjXy+vDouchAm6+A5Wjzv +J8wxVFDCs+9iGACmyUWr/JGXCYiQIbQkwlkRKHHlan9ymKf1NvIej/3EpeT8fKr6ywxGuhAfqofW +pg3WJY/RCB4lTzD8vZGNwfMFGkWhJkypad3i9w3lGmDVpsHaWtCgGfd0H7tUtWPkP+t7EjIRCD9J +HYnTR+wbbewc5vOI+UobR15ynGfFIaSIiMTVtQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEejCCA2KgAwIBAgIEP4vk6TANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQ +TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu +dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBD +QSBLbGFzYSAyMB4XDTAzMTAxNDExNTgyMloXDTE3MDQxODEyNTMwN1owdzELMAkG +A1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6IG8uby4xJDAiBgNV +BAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEhMB8GA1UEAxMYQ0MgU2ln +bmV0IC0gT0NTUCBLbGFzYSAyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCo +VCsaBStblXQYVNthe3dvaCrfvKpPXngh4almm988iIlEv9CVTaAdCfaJNihvA+Vs +Qw8++ix1VqteMQE474/MV/YaXigP0Zr0QB+g+/7PWVlv+5U9Gzp9+Xx4DJay8AoI +iB7Iy5Qf9iZiHm5BiPRIuUXT4ZRbZRYPh0/76vgRsQIDAQABo4IBkjCCAY4wDgYD +VR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEEGA1UdHwQ6MDgwNqA0 +oDKGMGh0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9jcmwva2xhc2Ey +LmNybDCB2AYDVR0gBIHQMIHNMIHKBg4rBgEEAb4/AoFICgwBADCBtzBsBggrBgEF +BQcCAjBgGl5DZXJ0eWZpa2F0IHd5ZGFueSB6Z29kbmllIHogZG9rdW1lbnRlbSAi +UG9saXR5a2EgQ2VydHlmaWthY2ppIC0gQ2VydHlmaWthdHkgcmVzcG9uZGVyb3cg +T0NTUCIuMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0 +b3JpdW0vZG9rdW1lbnR5L3BjX29jc3BfMV8wLnBkZjAfBgNVHSMEGDAWgBS7RQZS +C8uBzSlUs7x8QUzNBw6MJTAdBgNVHQ4EFgQUKEVrOY7cEHvsVgvoyZdytlbtgwEw +CQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEAQrRg5MV6dxr0HU2IsLInxhvt +iUVmSFkIUsBCjzLoewOXA16d2oDyHhI/eE+VgAsp+2ANjZu4xRteHIHoYMsN218M +eD2MLRsYS0U9xxAFK9gDj/KscPbrrdoqLvtPSMhUb4adJS9HLhvUe6BicvBf3A71 +iCNe431axGNDWKnpuj2KUpj4CFHYsWCXky847YtTXDjri9NIwJJauazsrSjK+oXp +ngRS506mdQ7vWrtApkh8zhhWp7duCkjcCo1O8JxqYr2qEW1fXmgOISe010v2mmuv +hHxPyVwoAU4KkOw0nbXZn53yak0is5+XmAjh0wWue44AssHrjC9nUh3mkLt6eQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEezCCA2OgAwIBAgIEP4vnLzANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJQ +TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEfMB0GA1UEAxMWQ0Mg +U2lnbmV0IC0gQ0EgS2xhc2EgMzEXMBUGA1UEBRMOTnVtZXIgd3Bpc3U6IDQwHhcN +MDMxMDE0MTIwODAwWhcNMDgwNDI4MTA1MDU1WjB3MQswCQYDVQQGEwJQTDEfMB0G +A1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBD +ZXJ0eWZpa2FjamkgU2lnbmV0MSEwHwYDVQQDExhDQyBTaWduZXQgLSBPQ1NQIEts +YXNhIDMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM/9GwvARNuCVN+PqZmO +4FqH8vTqhenUyqRkmAVT4YhLu0a9AXeLAYVDu+NTkYzsAUMAfu55rIKHNLlm6WbF +KvLiKKz4p4pbUr+ToPcwl/TDotidloUdBAxDg0SL+PmQqACZDe3seJho2IYf2vDL +/G4TLMbKmNB0mlWFuN0f4fJNAgMBAAGjggGgMIIBnDAOBgNVHQ8BAf8EBAMCB4Aw +EwYDVR0lBAwwCgYIKwYBBQUHAwkwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3 +dy5zaWduZXQucGwva3dhbGlmaWtvd2FuZS9yZXBvenl0b3JpdW0vY3JsL2tsYXNh +My5jcmwwgdgGA1UdIASB0DCBzTCBygYOKwYBBAG+PwKCLAoCAQAwgbcwbAYIKwYB +BQUHAgIwYBpeQ2VydHlmaWthdCB3eWRhbnkgemdvZG5pZSB6IGRva3VtZW50ZW0g +IlBvbGl0eWthIENlcnR5ZmlrYWNqaSAtIENlcnR5ZmlrYXR5IHJlc3BvbmRlcm93 +IE9DU1AiLjBHBggrBgEFBQcCARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5 +dG9yaXVtL2Rva3VtZW50eS9wY19vY3NwXzFfMC5wZGYwHwYDVR0jBBgwFoAUe2PM +GZB6tM62O559bRUnUND5SbkwHQYDVR0OBBYEFG4jnCMvBALRQXtmDn9TyXQ/EKP+ +MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADggEBACXrKG5Def5lpRwmZom3UEDq +bl7y4U3qomG4B+ok2FVZGgPZti+ZgvrenPj7PtbYCUBPsCSTNrznKinoT3gD9lQQ +xkEHwdc6VD1GlFp+qI64u0+wS9Epatrdf7aBnizrOIB4LJd4E2TWQ6trspetjMIU +upyWls1BmYUxB91R7QkTiAUSNZ87s3auhZuG4f0V0JLVCcg2rn7AN1rfMkgxCbHk +GxiQbYWFljl6aatxR3odnnzVUe1I8uoY2JXpmmUcOG4dNGuQYziyKG3mtXCQWvug +5qi9Mf3KUh1oSTKx6HfLjjNl1+wMB5Mdb8LF0XyZLdJM9yIZh7SBRsYm9QiXevY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFGjCCBAKgAwIBAgIEPL7eEDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE +ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg +U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDIwNDE4MTQ1NDA4WhcNMjYw +OTIxMTU0MjE5WjB2MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v +LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWdu +ZXQgLSBQQ0EgS2xhc2EgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM7BrBlbN5ma +M5eg0BOTqoZ+9NBDvU8Lm5rTdrMswFTCathzpVVLK/JD4K3+4oCZ9SRAspEXE4gvwb08ASY6w5s+ +HpRkeJw8YzMFR5kDZD5adgnCAy4vDfIXYZgppXPaTQ8wnfUZ7BZ7Zfa7QBemUIcJIzJBB0UqgtxW +Ceol9IekpBRVmuuSA6QG0Jkm+pGDJ05yj2eQG8jTcBENM7sVA8rGRMyFA4skSZ+D0OG6FS2xC1i9 +JyN0ag1yII/LPx8HK5J4W9MaPRNjAEeaa2qI9EpchwrOxnyVbQfSedCG1VRJfAsE/9tT9CMUPZ3x +W20QjQcSZJqVcmGW9gVsXKQOVLsCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQEBMIHkMIGaBggrBgEFBQcC +AjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 +eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6 +IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5z +aWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw +OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Evcm9vdGNhLmNy +bDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNVHQ4EFgQUwGxGyl2CfpYHRonE +82AVXO08kMIwDQYJKoZIhvcNAQEFBQADggEBABp1TAUsa+BeVWg4cjowc8yTJ5XN3GvN96GObMkx +UGY7U9kVrLI71xBgoNVyzXTiMNDBvjh7vdPWjpl5SDiRpnnKiOFXA43HvNWzUaOkTu1mxjJsZsan +ot1Xt6j0ZDC+03FjLHdYMyM9kSWp6afb4980EPYZCcSzgM5TOGfJmNii5Tq468VFKrX+52Aou1G2 +2Ohu+EEOlOrG7ylKv1hHUJJCjwN0ZVEIn1nDbrU9FeGCz8J9ihVUvnENEBbBkU37PWqWuHitKQDV +tcwTwJJdR8cmKq3NmkwAm9fPacidQLpaw0WkuGrS+fEDhu1Nhy9xELP6NA9GRTCNxm/dXlcwnmY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFGjCCBAKgAwIBAgIEPV0tNDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE +ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg +U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDIwODE2MTY0OTU2WhcNMjYw +OTIxMTU0MjE5WjB2MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v +LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWdu +ZXQgLSBQQ0EgS2xhc2EgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALN3LanJtdue +Ne6geWUTFENa+lEuzqELcoqhYB+a/tJcPEkc6TX/bYPzalRRjqs+quMP6KZTU0DixOrV+K7iWaqA +iQ913HX5IBLmKDCrTVW/ZvSDpiBKbxlHfSNuJxAuVT6HdbzK7yAW38ssX+yS2tZYHZ5FhZcfqzPE +OpO94mAKcBUhk6T/ki0evXX/ZvvktwmF3hKattzwtM4JMLurAEl8SInyEYULw5JdlfcBez2Tg6Db +w34hA1A+ckTwhxzecrB8TUe2BnQKOs9vr2cCACpFFcOmPkM0Drtjctr1QHm1tYSqRFRf9VcV5tfC +3P8QqoK4ONjtLPHc9x5NE1uK/FMCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQECMIHkMIGaBggrBgEFBQcC +AjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 +eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6 +IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5z +aWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw +OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Evcm9vdGNhLmNy +bDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNVHQ4EFgQUXvthcPHlH5BgGhlM +ErJNXWlhlgAwDQYJKoZIhvcNAQEFBQADggEBACIce95Mvn710KCAISA0CuHD4aznTU6pLoCDShW4 +7OR+GTpJUm1coTcUqlBHV9mra4VFrBcBuOkHZoBLq/jmE0QJWnpSEULDcH9J3mF0nqO9SM+mWyJG +dsJF/XU/7smummgjMNQXwzQTtWORF+6v5KUbWX85anO2wR+M6YTBWC55zWpWi4RG3vkHFs5Ze2oF +JTlpuxw9ZgxTnWlwI9QR2MvEhYIUMKMOWxw1nt0kKj+5TCNQQGh/VJJ1dsiroGh/io1DOcePEhKz +1Ag52y6Wf0nJJB9yk0sFakqZH18F7eQecQImgZyyeRtsG95leNugB3BXWCW+KxwiBrtQTXv4dTE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEzzCCA7egAwIBAgIEO6ocGTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE +ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg +U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDEwOTIwMTY0MjE5WhcNMjYw +OTIxMTU0MjE5WjBxMQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v +LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWdu +ZXQgLSBSb290Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrr2vydnNpELfGW3Ks +ARiDhJvwDtUe4AbWev+OfMc3+vA29nX8ZmIwno3gmItjo5DbUCCRiCMq5c9epcGu+kg4a3BJChVX +REl8gVh0ST15rr3RKrSc4VgsvQzl0ZUraeQLl8JoRT5PLsUj3qwF78jUCQVckiiLVcnGfZtFCm+D +CJXliQBDMB9XFAUEiO/DtEBs0B7wJGx7lgJeJpQUcGiaOPjcJDYOk7rNAYmmD2gWeSlepufO8luU +YG/YDxTC4mqhRqfa4MnVO5dqy+ICj2UvUpHbZDB0KfGRibgBYeQP1kuqgIzJN4UqknVAJb0aMBSP +l+9k2fAUdchx1njlbdcbAgMBAAGjggFtMIIBaTAPBgNVHRMBAf8EBTADAQH/MIIBBAYDVR0gBIH8 +MIH5MIH2Bg0rBgEEAb4/AgEKAQEAMIHkMIGaBggrBgEFBQcCAjCBjRqBikNlcnR5ZmlrYXQgd3lz +dGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBkbGEg +Um9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNoaWkg +Q0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVt +L2Rva3VtZW50eS9wY19yb290Y2EudHh0MB0GA1UdDgQWBBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAf +BgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcN +AQEFBQADggEBAGnY5QmYqnnO9OqFOWZxxb25UHRnaRF6IV9aaGit5BZufZj2Tq3v8L3SgE34GOoI +cdRMMG5JEpEU4mN/Ef3oY6Eo+7HfqaPHI4KFmbDSPiK5s+wmf+bQSm0Yq5/h4ZOdcAESlLQeLSt1 +CQk2JoKQJ6pyAf6xJBgWEIlm4RXE4J3324PUiOp83kW6MDvaa1xY976WyInr4rwoLgxVl11LZeKW +ha0RJJxJgw/NyWpKG7LWCm1fglF8JH51vZNndGYq1iKtfnrIOvLZq6bzaCiZm1EurD8HE6P7pmAB +KK6o3C2OXlNfNIgwkDN/cDqk5TYsTkrpfriJPdxXBH8hQOkW89g= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID/TCCA2agAwIBAgIEP4/gkTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQTDEfMB0GA1UE +ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg +U2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBDQSBLbGFzYSAxMB4XDTAzMTAxNzEyMjkwMloX +DTExMDkyMzExMTgxN1owdjELMAkGA1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6 +IG8uby4xJDAiBgNVBAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEgMB4GA1UEAxMXQ0Mg +U2lnbmV0IC0gVFNBIEtsYXNhIDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJYrISEtSsd +uHajROh5/n7NGrkpYTT9NEaPe9+ucuQ37KxIbfJwXJjgUc1dw4wCkcQ12FJarD1X6mSQ4cfN/60v +LfKI5ZD4nhJTMKlAj1pX9ScQ/MuyvKStCbn5WTkjPhjRAM0tdwXSnzuTEunfw0Oup559y3Iqxg1c +ExflB6cfAgMBAAGjggGXMIIBkzBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vd3d3LnNpZ25ldC5w +bC9yZXBvenl0b3JpdW0vY3JsL2tsYXNhMS5jcmwwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQM +MAoGCCsGAQUFBwMIMIHaBgNVHSAEgdIwgc8wgcwGDSsGAQQBvj8CZAoRAgEwgbowbwYIKwYBBQUH +AgIwYxphQ2VydHlmaWthdCB3eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVudGVtICJQb2xpdHlr +YSBDZXJ0eWZpa2FjamkgQ0MgU2lnbmV0IC0gWm5ha293YW5pZSBjemFzZW0iLjBHBggrBgEFBQcC +ARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY190c2ExXzJf +MS5wZGYwHwYDVR0jBBgwFoAUw4Me1Vl3VPtN+1dH+cQjXNHnieMwHQYDVR0OBBYEFJdDwEqtcavO +Yd9u9tej53vWXwNBMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADgYEAnpiQkqLCJQYXUrqMHUEz ++z3rOqS0XzSFnVVLhkVssvXc8S3FkJIiQTUrkScjI4CToCzujj3EyfNxH6yiLlMbskF8I31JxIeB +vueqV+s+o76CZm3ycu9hb0I4lswuxoT+q5ZzPR8Irrb51rZXlolR+7KtwMg4sFDJZ8RNgOf7tbA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEFTCCA36gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBvjELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UE +ChMfU29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9z +dG1hc3RlcjEgMB4GA1UEAxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkq +hkiG9w0BCQEWFmhvc3RtYXN0ZXJAc3BpLWluYy5vcmcwHhcNMDMwMTE1MTYyOTE3 +WhcNMDcwMTE0MTYyOTE3WjCBvjELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0luZGlh +bmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdhcmUgaW4g +dGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1hc3RlcjEgMB4GA1UE +AxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkqhkiG9w0BCQEWFmhvc3Rt +YXN0ZXJAc3BpLWluYy5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPB6 +rdoiLR3RodtM22LMcfwfqb5OrJNl7fwmvskgF7yP6sdD2bOfDIXhg9852jhY8/kL +VOFe1ELAL2OyN4RAxk0rliZQVgeTgqvgkOVIBbNwgnjN6mqtuWzFiPL+NXQExq40 +I3whM+4lEiwSHaV+MYxWanMdhc+kImT50LKfkxcdAgMBAAGjggEfMIIBGzAdBgNV +HQ4EFgQUB63oQR1/vda/G4F6P4xLiN4E0vowgesGA1UdIwSB4zCB4IAUB63oQR1/ +vda/G4F6P4xLiN4E0vqhgcSkgcEwgb4xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdJ +bmRpYW5hMRUwEwYDVQQHEwxJbmRpYW5hcG9saXMxKDAmBgNVBAoTH1NvZnR3YXJl +IGluIHRoZSBQdWJsaWMgSW50ZXJlc3QxEzARBgNVBAsTCmhvc3RtYXN0ZXIxIDAe +BgNVBAMTF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MSUwIwYJKoZIhvcNAQkBFhZo +b3N0bWFzdGVyQHNwaS1pbmMub3JnggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN +AQEEBQADgYEAm/Abn8c2y1nO3fgpAIslxvi9iNBZDhQtJ0VQZY6wgSfANyDOR4DW +iexO/AlorB49KnkFS7TjCAoLOZhcg5FaNiKnlstMI5krQmau1Qnb/vGSNsE/UGms +1ts+QYPUs0KmGEAFUri2XzLy+aQo9Kw74VBvqnxvaaMeY5yMcKNOieY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIIDjCCBfagAwIBAgIJAOiOtsn4KhQoMA0GCSqGSIb3DQEBBQUAMIG8MQswCQYD +VQQGEwJVUzEQMA4GA1UECBMHSW5kaWFuYTEVMBMGA1UEBxMMSW5kaWFuYXBvbGlz +MSgwJgYDVQQKEx9Tb2Z0d2FyZSBpbiB0aGUgUHVibGljIEludGVyZXN0MRMwEQYD +VQQLEwpob3N0bWFzdGVyMR4wHAYDVQQDExVDZXJ0aWZpY2F0ZSBBdXRob3JpdHkx +JTAjBgkqhkiG9w0BCQEWFmhvc3RtYXN0ZXJAc3BpLWluYy5vcmcwHhcNMDgwNTEz +MDgwNzU2WhcNMTgwNTExMDgwNzU2WjCBvDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdh +cmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1hc3RlcjEe +MBwGA1UEAxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSUwIwYJKoZIhvcNAQkBFhZo +b3N0bWFzdGVyQHNwaS1pbmMub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEA3DbmR0LCxFF1KYdAw9iOIQbSGE7r7yC9kDyFEBOMKVuUY/b0LfEGQpG5 +GcRCaQi/izZF6igFM0lIoCdDkzWKQdh4s/Dvs24t3dHLfer0dSbTPpA67tfnLAS1 +fOH1fMVO73e9XKKTM5LOfYFIz2u1IiwIg/3T1c87Lf21SZBb9q1NE8re06adU1Fx +Y0b4ShZcmO4tbZoWoXaQ4mBDmdaJ1mwuepiyCwMs43pPx93jzONKao15Uvr0wa8u +jyoIyxspgpJyQ7zOiKmqp4pRQ1WFmjcDeJPI8L20QcgHQprLNZd6ioFl3h1UCAHx +ZFy3FxpRvB7DWYd2GBaY7r/2Z4GLBjXFS21ZGcfSxki+bhQog0oQnBv1b7ypjvVp +/rLBVcznFMn5WxRTUQfqzj3kTygfPGEJ1zPSbqdu1McTCW9rXRTunYkbpWry9vjQ +co7qch8vNGopCsUK7BxAhRL3pqXTT63AhYxMfHMgzFMY8bJYTAH1v+pk1Vw5xc5s +zFNaVrpBDyXfa1C2x4qgvQLCxTtVpbJkIoRRKFauMe5e+wsWTUYFkYBE7axt8Feo ++uthSKDLG7Mfjs3FIXcDhB78rKNDCGOM7fkn77SwXWfWT+3Qiz5dW8mRvZYChD3F +TbxCP3T9PF2sXEg2XocxLxhsxGjuoYvJWdAY4wCAs1QnLpnwFVMCAwEAAaOCAg8w +ggILMB0GA1UdDgQWBBQ0cdE41xU2g0dr1zdkQjuOjVKdqzCB8QYDVR0jBIHpMIHm +gBQ0cdE41xU2g0dr1zdkQjuOjVKdq6GBwqSBvzCBvDELMAkGA1UEBhMCVVMxEDAO +BgNVBAgTB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMf +U29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1h +c3RlcjEeMBwGA1UEAxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSUwIwYJKoZIhvcN +AQkBFhZob3N0bWFzdGVyQHNwaS1pbmMub3JnggkA6I62yfgqFCgwDwYDVR0TAQH/ +BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAAcwCQYDVR0SBAIwADAuBglghkgBhvhC +AQ0EIRYfU29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDAwBglghkgBhvhC +AQQEIxYhaHR0cHM6Ly9jYS5zcGktaW5jLm9yZy9jYS1jcmwucGVtMDIGCWCGSAGG ++EIBAwQlFiNodHRwczovL2NhLnNwaS1pbmMub3JnL2NlcnQtY3JsLnBlbTAhBgNV +HREEGjAYgRZob3N0bWFzdGVyQHNwaS1pbmMub3JnMA4GA1UdDwEB/wQEAwIBBjAN +BgkqhkiG9w0BAQUFAAOCAgEAtM294LnqsgMrfjLp3nI/yUuCXp3ir1UJogxU6M8Y +PCggHam7AwIvUjki+RfPrWeQswN/2BXja367m1YBrzXU2rnHZxeb1NUON7MgQS4M +AcRb+WU+wmHo0vBqlXDDxm/VNaSsWXLhid+hoJ0kvSl56WEq2dMeyUakCHhBknIP +qxR17QnwovBc78MKYiC3wihmrkwvLo9FYyaW8O4x5otVm6o6+YI5HYg84gd1GuEP +sTC8cTLSOv76oYnzQyzWcsR5pxVIBcDYLXIC48s9Fmq6ybgREOJJhcyWR2AFJS7v +dVkz9UcZFu/abF8HyKZQth3LZjQl/GaD68W2MEH4RkRiqMEMVObqTFoo5q7Gt/5/ +O5aoLu7HaD7dAD0prypjq1/uSSotxdz70cbT0ZdWUoa2lOvUYFG3/B6bzAKb1B+P ++UqPti4oOxfMxaYF49LTtcYDyeFIQpvLP+QX4P4NAZUJurgNceQJcHdC2E3hQqlg +g9cXiUPS1N2nGLar1CQlh7XU4vwuImm9rWgs/3K1mKoGnOcqarihk3bOsPN/nOHg +T7jYhkalMwIsJWE3KpLIrIF0aGOHM3a9BX9e1dUCbb2v/ypaqknsmHlHU5H2DjRa +yaXG67Ljxay2oHA1u8hRadDytaIybrw/oDc5fHE2pgXfDBLkFqfF1stjo5VwP+YE +o2A= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc +MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj +IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB +IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE +RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl +U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 +IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU +ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC +QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr +rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S +NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc +QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH +txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP +BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC +AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp +tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa +IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl +6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ +xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx +ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw +MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH +QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j +b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j +b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H +KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm +VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR +SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT +cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ +6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu +MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS +kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB +BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f +BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv +c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH +AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO +BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG +OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU +A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o +0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX +RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH +qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV +U+4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh +bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu +Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g +QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe +BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX +DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE +YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC +ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q +N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO +r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN +f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH +U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU +TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb +VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg +SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv +biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg +MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw +AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv +ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu +Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd +IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv +bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1 +QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O +WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf +SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz +BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y +aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG +9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy +NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y +azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw +Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl +cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY +dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 +WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS +v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v +UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu +IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC +W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd +-----END CERTIFICATE----- diff --git a/tests/vcore/test-cases/keys/README b/tests/vcore/test-cases/keys/README new file mode 100644 index 0000000..c7151d6 --- /dev/null +++ b/tests/vcore/test-cases/keys/README @@ -0,0 +1,2 @@ +This directory contains certificate/public keys/private keys used to create unittests. +Passwort to private keys is "1234" or "secret". \ No newline at end of file diff --git a/tests/vcore/test-cases/keys/filip_rsa_cert.pem b/tests/vcore/test-cases/keys/filip_rsa_cert.pem new file mode 100644 index 0000000..0abebc6 --- /dev/null +++ b/tests/vcore/test-cases/keys/filip_rsa_cert.pem @@ -0,0 +1,62 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + c7:4a:82:f6:9d:1b:f6:7e + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=PL, ST=Maz, O=Samsung, OU=SPRC, CN=Samsung/emailAddress=samsung@samsung.com + Validity + Not Before: Oct 5 12:00:51 2011 GMT + Not After : Oct 2 12:00:51 2021 GMT + Subject: C=PL, ST=MAZ, L=Leg, O=Sam, OU=SPRC, CN=Filip/emailAddress=filip@samsung.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:d2:fe:c4:b4:c1:74:82:6f:7e:28:8c:df:1b:58: + 57:78:3e:5f:5e:4c:b1:e1:d7:c5:0d:1a:c3:e9:2e: + 9a:78:8a:d7:5f:b9:cf:ce:83:2a:9a:4a:80:f0:07: + 35:61:11:60:15:2c:24:f1:7b:15:1a:e0:d7:2f:6b: + ee:35:35:b9:16:e1:10:ac:17:37:86:b3:49:2d:a6: + ed:7e:f1:0f:af:d1:01:0e:1a:a5:45:da:b4:24:82: + 29:73:0c:5f:e8:3b:9e:85:c7:0f:6f:1b:53:80:fa: + a7:50:77:7c:8e:01:5d:84:a8:b3:41:3e:b1:18:07: + d2:b9:18:5c:9f:7e:b6:a4:49 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 7B:2C:B7:89:5E:F9:2A:D3:A4:A4:F1:5D:EA:69:D1:F5:D1:46:64:CC + X509v3 Authority Key Identifier: + keyid:82:08:7F:DB:00:02:86:E8:53:2A:A5:FA:58:AE:67:7F:14:38:C8:60 + + Signature Algorithm: sha1WithRSAEncryption + 0e:db:f4:08:1a:d0:d5:00:8c:1f:d8:ca:16:3a:52:a6:ae:f3: + 14:a3:17:41:e5:6d:6f:f6:62:7b:cd:b7:ff:fc:28:89:c8:3c: + 93:19:cf:e6:c4:b8:74:95:8d:5c:d6:f5:88:c2:dd:86:05:7c: + d2:0d:72:b7:78:13:58:fc:53:b4:5c:e9:ad:0c:8d:88:91:d3: + 9a:b6:cd:59:72:d7:d6:ba:11:54:65:04:fc:8f:10:e3:17:b1: + aa:96:cd:94:92:16:d8:98:e6:fe:4a:a8:29:f9:ca:c4:e4:46: + e8:73:4f:5d:95:76:f4:d6:36:7c:34:4f:3c:e2:18:a0:54:33: + ad:72 +-----BEGIN CERTIFICATE----- +MIIC4zCCAkygAwIBAgIJAMdKgvadG/Z+MA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV +BAYTAlBMMQwwCgYDVQQIEwNNYXoxEDAOBgNVBAoTB1NhbXN1bmcxDTALBgNVBAsT +BFNQUkMxEDAOBgNVBAMTB1NhbXN1bmcxIjAgBgkqhkiG9w0BCQEWE3NhbXN1bmdA +c2Ftc3VuZy5jb20wHhcNMTExMDA1MTIwMDUxWhcNMjExMDAyMTIwMDUxWjB4MQsw +CQYDVQQGEwJQTDEMMAoGA1UECBMDTUFaMQwwCgYDVQQHEwNMZWcxDDAKBgNVBAoT +A1NhbTENMAsGA1UECxMEU1BSQzEOMAwGA1UEAxMFRmlsaXAxIDAeBgkqhkiG9w0B +CQEWEWZpbGlwQHNhbXN1bmcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQDS/sS0wXSCb34ojN8bWFd4Pl9eTLHh18UNGsPpLpp4itdfuc/OgyqaSoDwBzVh +EWAVLCTxexUa4Ncva+41NbkW4RCsFzeGs0ktpu1+8Q+v0QEOGqVF2rQkgilzDF/o +O56Fxw9vG1OA+qdQd3yOAV2EqLNBPrEYB9K5GFyffrakSQIDAQABo3sweTAJBgNV +HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp +Y2F0ZTAdBgNVHQ4EFgQUeyy3iV75KtOkpPFd6mnR9dFGZMwwHwYDVR0jBBgwFoAU +ggh/2wAChuhTKqX6WK5nfxQ4yGAwDQYJKoZIhvcNAQEFBQADgYEADtv0CBrQ1QCM +H9jKFjpSpq7zFKMXQeVtb/Zie823//woicg8kxnP5sS4dJWNXNb1iMLdhgV80g1y +t3gTWPxTtFzprQyNiJHTmrbNWXLX1roRVGUE/I8Q4xexqpbNlJIW2Jjm/kqoKfnK +xORG6HNPXZV29NY2fDRPPOIYoFQzrXI= +-----END CERTIFICATE----- diff --git a/tests/vcore/test-cases/keys/filip_rsa_key.pem b/tests/vcore/test-cases/keys/filip_rsa_key.pem new file mode 100644 index 0000000..6d0f4d8 --- /dev/null +++ b/tests/vcore/test-cases/keys/filip_rsa_key.pem @@ -0,0 +1,18 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,FDE9F633EA955697 + +ASWLPmOFfKlo46nJXTJLCkhvD/q1MsHXPaaSByVzaavXxwMxOc2g7VkIR2D0yViQ +mxQFhJLVeq/1UI9pXL2+zk0awptHogwjTw81r2I+R6qkHsSjGjl4Ds6hOX3J211K +UqO4+3kf6JJOizXbH/y6WWbj9jEJeE7zzmhuyq8k6Kp47leZsle5y13usii323tz +OgAzZGsQBSkrlBNKKM58O7TkCO6UbZLjVEoBqcJU+p+UiKoGKdUV/MxkbGEKTEPN +wrFiqIxSk9KuV5iDAjnYCPz6iQIE+Q3NOW+MTw0yjWoMb7uXJexGM6VYkYFZUffe +16nAzJpYbG+CsJ5XTiGoiodazloVYdnDFnbDLDGS2kLgiuuHzF/DL1lFlbXwgpGj +sXFp6CemJ+KnMz4aIfC63Wuav+jvAVw26pl/cYxbhboSkl+H9ZKbk+KcIeMN1Rb7 +LD35tsjO5rnQ1QlG0WP6qT6O1SPG/4GgJTyzTwuw6i8jQw62ahKB5hTri/Z8Fmrn +kFh8F7gTJ+YnxrQuTK8r9QrZrXsE/YqUbHtVEI/m/6uydWdFHNWzJxe6oavuwks2 +3mumh1101mBEuEClzOzHP925oeXW+N8R+jFnA/7NkIjeOo+J9Z+QzBiq6DVJcuEY +5aqXcCIS9AciUoh3/ovtT637r25nhYwCruZLZ+4+Vkpv9n/gPSipHXgHt2cynaID +6O7xyoADa+zY1zTRd+A4aA+SWd/bxvKe+6sc/6iBlKA8bKwfPJcwg7il4bX4g5dk +dI8gTyM9puDoHrdTaLwY8+JL0MCguEvkk7LDttNfN0gxYvxXTpZ+Tg== +-----END RSA PRIVATE KEY----- diff --git a/tests/vcore/test-cases/keys/magda_dsa_cert.pem b/tests/vcore/test-cases/keys/magda_dsa_cert.pem new file mode 100644 index 0000000..0348db8 --- /dev/null +++ b/tests/vcore/test-cases/keys/magda_dsa_cert.pem @@ -0,0 +1,90 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + c7:4a:82:f6:9d:1b:f6:7f + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=PL, ST=Maz, O=Samsung, OU=SPRC, CN=Samsung/emailAddress=samsung@samsung.com + Validity + Not Before: Oct 5 12:11:33 2011 GMT + Not After : Oct 2 12:11:33 2021 GMT + Subject: C=PL, ST=Mazowieckie, L=legionowo, O=samsung, OU=sprc, CN=magda/emailAddress=magda@samsung.com + Subject Public Key Info: + Public Key Algorithm: dsaEncryption + DSA Public Key: + pub: + 00:ac:40:42:0e:cc:a8:28:24:0b:43:09:7e:d6:23: + 35:a2:8c:e6:7d:62:66:fe:23:d6:58:b8:f7:32:9f: + 63:99:d3:2c:ff:af:60:0b:e0:d2:8c:0b:35:8b:c9: + e6:77:0a:7d:8d:43:00:23:d4:e3:ff:ad:0b:b4:d3: + b9:af:79:c2:08:f9:af:0b:c0:5e:7c:e0:4b:23:86: + b9:2a:f4:7c:af:43:ca:b1:fa:13:42:df:5d:3f:96: + b8:84:07:6a:19:b6:89:26:f1:a8:fa:c2:86:59:e9: + e7:f1:17:0d:30:5a:3b:a4:1f:76:9a:b4:04:fe:3c: + 0a:56:5e:6f:17:00:f9:36:05 + P: + 00:b5:3c:23:9a:b0:58:65:7c:c7:35:ca:37:5c:a7: + bc:e4:cd:71:a2:5b:e3:29:56:e1:65:b1:d6:30:90: + 06:bd:b0:8b:cd:ad:02:e2:da:e9:71:72:73:41:78: + 21:ca:0d:b9:3b:53:e2:77:fd:0c:0e:d9:76:a7:6a: + 94:0c:52:ab:df:8d:f8:cb:d5:04:39:55:fe:c4:35: + 45:8f:34:fe:dc:12:fc:7c:d8:d6:f9:8d:67:47:c9: + 17:d5:ff:f4:dc:88:16:4d:f0:62:cd:11:b7:e1:b5: + 69:61:23:a0:9b:0d:6d:40:69:8d:27:3d:9f:3b:f6: + b4:88:93:bf:da:34:a6:77:15 + Q: + 00:b7:2b:f2:e4:00:9a:75:7e:dc:32:c8:03:99:d3: + a3:40:60:d1:b8:cb + G: + 24:6e:e6:79:4b:50:6c:cb:a5:44:c7:63:cd:e0:a8: + c9:ad:85:5d:d9:be:e1:a7:2f:22:71:3d:ff:e3:32: + 6d:74:c1:dd:b1:40:34:cc:b0:e9:64:ef:93:82:bd: + 44:af:2d:9b:9d:8d:f7:97:32:91:38:e9:01:bc:6a: + 4c:c6:97:c2:47:56:6c:e1:5d:54:a0:0a:9f:2c:62: + fd:42:ad:63:d4:3a:36:6c:09:07:68:5b:03:51:94: + ce:13:e4:a3:ca:c4:75:ae:ba:08:69:74:55:bc:8c: + d6:52:8c:26:30:3e:c2:9f:69:1b:5d:74:2f:4a:2f: + d7:d4:3d:7e:fa:8a:a7:95 + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 99:2A:52:86:CC:2F:5A:D1:00:05:DF:A5:DD:6C:5C:71:17:02:C9:D5 + X509v3 Authority Key Identifier: + keyid:82:08:7F:DB:00:02:86:E8:53:2A:A5:FA:58:AE:67:7F:14:38:C8:60 + + Signature Algorithm: sha1WithRSAEncryption + 81:f9:c0:bb:f8:0c:25:10:bf:04:5c:24:82:fa:c7:2f:44:d5: + e1:f7:cf:54:07:fb:45:29:d9:4b:a8:9b:e0:81:c6:82:bb:d7: + 26:f2:fe:42:1e:ef:1f:29:2f:64:8a:83:d8:bf:7a:9d:8d:84: + 69:23:6b:d3:25:eb:4f:cd:58:44:e9:dd:39:05:09:37:1e:18: + fd:6f:26:e9:ab:2e:e2:1c:c0:34:d6:6a:58:26:c0:a4:f0:c8: + 30:ae:95:70:f0:35:c2:b2:a0:66:a6:d6:a7:6d:7c:58:1a:88: + da:ff:69:5d:5d:0e:fa:3a:73:c6:ad:7e:19:e4:15:d9:4b:1b: + 47:07 +-----BEGIN CERTIFICATE----- +MIIEDzCCA3igAwIBAgIJAMdKgvadG/Z/MA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV +BAYTAlBMMQwwCgYDVQQIEwNNYXoxEDAOBgNVBAoTB1NhbXN1bmcxDTALBgNVBAsT +BFNQUkMxEDAOBgNVBAMTB1NhbXN1bmcxIjAgBgkqhkiG9w0BCQEWE3NhbXN1bmdA +c2Ftc3VuZy5jb20wHhcNMTExMDA1MTIxMTMzWhcNMjExMDAyMTIxMTMzWjCBijEL +MAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93aWVja2llMRIwEAYDVQQHEwlsZWdp +b25vd28xEDAOBgNVBAoTB3NhbXN1bmcxDTALBgNVBAsTBHNwcmMxDjAMBgNVBAMT +BW1hZ2RhMSAwHgYJKoZIhvcNAQkBFhFtYWdkYUBzYW1zdW5nLmNvbTCCAbcwggEr +BgcqhkjOOAQBMIIBHgKBgQC1PCOasFhlfMc1yjdcp7zkzXGiW+MpVuFlsdYwkAa9 +sIvNrQLi2ulxcnNBeCHKDbk7U+J3/QwO2XanapQMUqvfjfjL1QQ5Vf7ENUWPNP7c +Evx82Nb5jWdHyRfV//TciBZN8GLNEbfhtWlhI6CbDW1AaY0nPZ879rSIk7/aNKZ3 +FQIVALcr8uQAmnV+3DLIA5nTo0Bg0bjLAoGAJG7meUtQbMulRMdjzeCoya2FXdm+ +4acvInE9/+MybXTB3bFANMyw6WTvk4K9RK8tm52N95cykTjpAbxqTMaXwkdWbOFd +VKAKnyxi/UKtY9Q6NmwJB2hbA1GUzhPko8rEda66CGl0VbyM1lKMJjA+wp9pG110 +L0ov19Q9fvqKp5UDgYUAAoGBAKxAQg7MqCgkC0MJftYjNaKM5n1iZv4j1li49zKf +Y5nTLP+vYAvg0owLNYvJ5ncKfY1DACPU4/+tC7TTua95wgj5rwvAXnzgSyOGuSr0 +fK9DyrH6E0LfXT+WuIQHahm2iSbxqPrChlnp5/EXDTBaO6Qfdpq0BP48ClZebxcA ++TYFo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVy +YXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUmSpShswvWtEABd+l3WxccRcCydUw +HwYDVR0jBBgwFoAUggh/2wAChuhTKqX6WK5nfxQ4yGAwDQYJKoZIhvcNAQEFBQAD +gYEAgfnAu/gMJRC/BFwkgvrHL0TV4ffPVAf7RSnZS6ib4IHGgrvXJvL+Qh7vHykv +ZIqD2L96nY2EaSNr0yXrT81YROndOQUJNx4Y/W8m6asu4hzANNZqWCbApPDIMK6V +cPA1wrKgZqbWp218WBqI2v9pXV0O+jpzxq1+GeQV2UsbRwc= +-----END CERTIFICATE----- diff --git a/tests/vcore/test-cases/keys/magda_dsa_key.pem b/tests/vcore/test-cases/keys/magda_dsa_key.pem new file mode 100644 index 0000000..7842af6 --- /dev/null +++ b/tests/vcore/test-cases/keys/magda_dsa_key.pem @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQC1PCOasFhlfMc1yjdcp7zkzXGiW+MpVuFlsdYwkAa9sIvNrQLi +2ulxcnNBeCHKDbk7U+J3/QwO2XanapQMUqvfjfjL1QQ5Vf7ENUWPNP7cEvx82Nb5 +jWdHyRfV//TciBZN8GLNEbfhtWlhI6CbDW1AaY0nPZ879rSIk7/aNKZ3FQIVALcr +8uQAmnV+3DLIA5nTo0Bg0bjLAoGAJG7meUtQbMulRMdjzeCoya2FXdm+4acvInE9 +/+MybXTB3bFANMyw6WTvk4K9RK8tm52N95cykTjpAbxqTMaXwkdWbOFdVKAKnyxi +/UKtY9Q6NmwJB2hbA1GUzhPko8rEda66CGl0VbyM1lKMJjA+wp9pG110L0ov19Q9 +fvqKp5UCgYEArEBCDsyoKCQLQwl+1iM1oozmfWJm/iPWWLj3Mp9jmdMs/69gC+DS +jAs1i8nmdwp9jUMAI9Tj/60LtNO5r3nCCPmvC8BefOBLI4a5KvR8r0PKsfoTQt9d +P5a4hAdqGbaJJvGo+sKGWenn8RcNMFo7pB92mrQE/jwKVl5vFwD5NgUCFC0583uX +PgTY5e9pOTVpCwebt50S +-----END DSA PRIVATE KEY----- diff --git a/tests/vcore/test-cases/keys/ocsp_level0deprecated.crt b/tests/vcore/test-cases/keys/ocsp_level0deprecated.crt new file mode 100644 index 0000000..67bfa31 --- /dev/null +++ b/tests/vcore/test-cases/keys/ocsp_level0deprecated.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVTCCBD2gAwIBAgIHBBrt1FojCzANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE +BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY +BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm +aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5 +IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky +ODcwHhcNMTAwNjA5MDIwNzU3WhcNMTEwNjE5MTEwNDM2WjBRMRUwEwYDVQQKEwwq +LnVidW50dS5jb20xITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEV +MBMGA1UEAxMMKi51YnVudHUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAu8VcCeGdREV3PYYQukyrfUAay8Ic3fMhA+YUKzqbH8UuPhcjjS3izxaT +vHLh7v80HS4DXYu6CqoQugZndV4R9KqJN1HVK5acar91VOeQgTSoowTSFtyg6aXJ +JVdEETyftGHSpS4WjyQZ9FazTfC47c5lJr+3wCZ90UaxaWpNERpMc2L4ZxG1wGCw +XYWVONtV817NecZVAiytvNPSmcnFm/OC/5GtzxNhfYmsNt1+MiC3IUFe2XnQwFhG +rvn9IcG2RhEKOOu55pHM08FcnDbfyegBkEDAmQbFIUM+tFUI7nkDNQWy/Mgzuqtg +DjydGu8h7BObEFrqXtUpm9CbTFZgzwIDAQABo4IBtjCCAbIwDwYDVR0TAQH/BAUw +AwEBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDgYDVR0PAQH/BAQD +AgWgMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Rz +MS0xOS5jcmwwUwYDVR0gBEwwSjBIBgtghkgBhv1tAQcXATA5MDcGCCsGAQUFBwIB +FitodHRwOi8vY2VydGlmaWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMIGA +BggrBgEFBQcBAQR0MHIwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmdvZGFkZHku +Y29tLzBKBggrBgEFBQcwAoY+aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv +bS9yZXBvc2l0b3J5L2dkX2ludGVybWVkaWF0ZS5jcnQwHwYDVR0jBBgwFoAU/axh +MpNsRdbi7oVfmrrndplozOcwIwYDVR0RBBwwGoIMKi51YnVudHUuY29tggp1YnVu +dHUuY29tMB0GA1UdDgQWBBTUVPFNlBiCNfPjhD8O8mDUv7MLUjANBgkqhkiG9w0B +AQUFAAOCAQEAUjuOqqu+vS0StsxVXj44hvPye1MC/MkanIrdce5BgYMc5a+8UJba +ay8h34vtsvfDsTifNY8ijDx79Hprh9V2LwfWWAiWK2SdrceIdGrxDvzmDHllO5YT +ig2XhAA7ll4toSnrUfsZmi/bgb1V6VNoq36xvK+riDGnPhc7tNDZZb1fBKE+nA1p +CZq80Liv1xri4Nj1YQ0kMQQnSHkUgEGg7bvtf+cNkIp3OXTNW8f7VFoaWVZNKW8c +cxNljypjJM+h7xXCG/YRKws8eCi+xpO1Oc41tnSvbCbc0B6+xwFjRx5tfja309QI +R2+uBFsmWtBCtn31o4CFNytEnwBOPVbZBA== +-----END CERTIFICATE----- diff --git a/tests/vcore/test-cases/keys/ocsp_level1.crt b/tests/vcore/test-cases/keys/ocsp_level1.crt new file mode 100644 index 0000000..b6276d4 --- /dev/null +++ b/tests/vcore/test-cases/keys/ocsp_level1.crt @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx +ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw +MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH +QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j +b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j +b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H +KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm +VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR +SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT +cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ +6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu +MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS +kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB +BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f +BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv +c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH +AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO +BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG +OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU +A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o +0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX +RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH +qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV +U+4= +-----END CERTIFICATE----- diff --git a/tests/vcore/test-cases/keys/ocsp_level2.crt b/tests/vcore/test-cases/keys/ocsp_level2.crt new file mode 100644 index 0000000..ec9fc33 --- /dev/null +++ b/tests/vcore/test-cases/keys/ocsp_level2.crt @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh +bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu +Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g +QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe +BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX +DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE +YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC +ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q +N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO +r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN +f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH +U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU +TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb +VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg +SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv +biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg +MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw +AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv +ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu +Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd +IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv +bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1 +QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O +WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf +SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw== +-----END CERTIFICATE----- diff --git a/tests/vcore/test-cases/keys/ocsp_rootca.crt b/tests/vcore/test-cases/keys/ocsp_rootca.crt new file mode 100644 index 0000000..8417dc7 --- /dev/null +++ b/tests/vcore/test-cases/keys/ocsp_rootca.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz +BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y +aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG +9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy +NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y +azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw +Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl +cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY +dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 +WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS +v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v +UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu +IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC +W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd +-----END CERTIFICATE----- diff --git a/tests/vcore/test-cases/keys/operator.root.cert.pem b/tests/vcore/test-cases/keys/operator.root.cert.pem new file mode 100644 index 0000000..343241f --- /dev/null +++ b/tests/vcore/test-cases/keys/operator.root.cert.pem @@ -0,0 +1,66 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 85:7d:e1:c5:d9:de:7a:1f + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=PL, ST=Mazowieckie, O=Samsung, OU=SPRC, CN=Operator Test Root Certificate/emailAddress=operator@samsung.com + Validity + Not Before: Jan 4 17:27:08 2011 GMT + Not After : Jan 3 17:27:08 2014 GMT + Subject: C=PL, ST=Mazowieckie, O=Samsung, OU=SPRC, CN=Operator Test Root Certificate/emailAddress=operator@samsung.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:c3:39:17:a8:f9:d0:69:37:9a:56:44:39:67:10: + 14:a9:4b:a2:0b:c7:fc:a1:e8:e8:f7:1c:06:f4:9c: + 83:f7:37:07:9d:9c:2c:1b:46:43:5f:f1:7b:91:a8: + cd:c0:76:00:d5:9c:c9:28:f7:91:28:b6:97:ec:85: + b1:10:0f:58:2e:f6:6f:98:b6:ab:7b:ca:08:10:7f: + 55:32:bf:32:db:a7:c2:86:83:03:ee:41:0a:24:de: + 17:e3:9d:8f:5b:fa:46:70:78:98:b4:c1:14:77:44: + ab:59:7c:4c:d3:4a:f7:54:f2:30:0d:38:73:95:9f: + 21:0e:a9:86:3e:fc:82:4e:0b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 25:A5:90:9F:4D:3A:A4:19:0A:80:46:5E:F3:FB:20:CE:56:30:33:DA + X509v3 Authority Key Identifier: + keyid:25:A5:90:9F:4D:3A:A4:19:0A:80:46:5E:F3:FB:20:CE:56:30:33:DA + DirName:/C=PL/ST=Mazowieckie/O=Samsung/OU=SPRC/CN=Operator Test Root Certificate/emailAddress=operator@samsung.com + serial:85:7D:E1:C5:D9:DE:7A:1F + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + b9:d7:72:49:09:d8:6f:61:94:51:40:9d:c3:d3:23:53:97:b8: + 12:ee:cb:dd:57:e6:1f:a2:76:38:5d:42:51:bd:a9:30:19:f7: + 67:5b:a8:67:4a:9e:a1:f0:a9:22:14:94:77:32:27:79:37:9c: + 0a:0f:52:80:14:62:00:94:45:85:3b:fd:ad:b4:c3:20:45:ba: + b7:91:1a:9e:38:51:0f:9b:d5:ce:74:c7:bd:4a:21:9a:2d:b5: + 71:0b:42:d2:95:72:66:fe:eb:11:ad:62:44:6c:32:4e:b4:00: + 37:d7:b8:d5:4b:f6:74:36:78:d6:ae:66:b3:ca:6e:42:ff:cb: + c2:e6 +-----BEGIN CERTIFICATE----- +MIIDnzCCAwigAwIBAgIJAIV94cXZ3nofMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYD +VQQGEwJQTDEUMBIGA1UECBMLTWF6b3dpZWNraWUxEDAOBgNVBAoTB1NhbXN1bmcx +DTALBgNVBAsTBFNQUkMxJzAlBgNVBAMTHk9wZXJhdG9yIFRlc3QgUm9vdCBDZXJ0 +aWZpY2F0ZTEjMCEGCSqGSIb3DQEJARYUb3BlcmF0b3JAc2Ftc3VuZy5jb20wHhcN +MTEwMTA0MTcyNzA4WhcNMTQwMTAzMTcyNzA4WjCBkjELMAkGA1UEBhMCUEwxFDAS +BgNVBAgTC01hem93aWVja2llMRAwDgYDVQQKEwdTYW1zdW5nMQ0wCwYDVQQLEwRT +UFJDMScwJQYDVQQDEx5PcGVyYXRvciBUZXN0IFJvb3QgQ2VydGlmaWNhdGUxIzAh +BgkqhkiG9w0BCQEWFG9wZXJhdG9yQHNhbXN1bmcuY29tMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDDOReo+dBpN5pWRDlnEBSpS6ILx/yh6Oj3HAb0nIP3Nwed +nCwbRkNf8XuRqM3AdgDVnMko95EotpfshbEQD1gu9m+Ytqt7yggQf1UyvzLbp8KG +gwPuQQok3hfjnY9b+kZweJi0wRR3RKtZfEzTSvdU8jANOHOVnyEOqYY+/IJOCwID +AQABo4H6MIH3MB0GA1UdDgQWBBQlpZCfTTqkGQqARl7z+yDOVjAz2jCBxwYDVR0j +BIG/MIG8gBQlpZCfTTqkGQqARl7z+yDOVjAz2qGBmKSBlTCBkjELMAkGA1UEBhMC +UEwxFDASBgNVBAgTC01hem93aWVja2llMRAwDgYDVQQKEwdTYW1zdW5nMQ0wCwYD +VQQLEwRTUFJDMScwJQYDVQQDEx5PcGVyYXRvciBUZXN0IFJvb3QgQ2VydGlmaWNh +dGUxIzAhBgkqhkiG9w0BCQEWFG9wZXJhdG9yQHNhbXN1bmcuY29tggkAhX3hxdne +eh8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQC513JJCdhvYZRRQJ3D +0yNTl7gS7svdV+YfonY4XUJRvakwGfdnW6hnSp6h8KkiFJR3Mid5N5wKD1KAFGIA +lEWFO/2ttMMgRbq3kRqeOFEPm9XOdMe9SiGaLbVxC0LSlXJm/usRrWJEbDJOtAA3 +17jVS/Z0NnjWrmazym5C/8vC5g== +-----END CERTIFICATE----- diff --git a/tests/vcore/test-cases/keys/operator.second.cert.pem b/tests/vcore/test-cases/keys/operator.second.cert.pem new file mode 100644 index 0000000..f062d94 --- /dev/null +++ b/tests/vcore/test-cases/keys/operator.second.cert.pem @@ -0,0 +1,64 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 85:7d:e1:c5:d9:de:7a:20 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=PL, ST=Mazowieckie, O=Samsung, OU=SPRC, CN=Operator Test Root Certificate/emailAddress=operator@samsung.com + Validity + Not Before: Jan 4 17:34:31 2011 GMT + Not After : Jan 4 17:34:31 2012 GMT + Subject: C=PL, ST=Malopolskie, L=Krakow, O=Samsung, OU=N/A, CN=Operator Test Second Level Certificate/emailAddress=second.operator@samsung.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:ba:3c:58:ca:87:1e:59:68:54:8a:54:34:43:61: + f1:81:e6:35:c1:46:74:16:c7:ff:f9:15:9e:0c:5a: + 6a:89:c1:13:0c:61:2e:ba:00:e0:71:ea:7e:31:ae: + 4e:ef:93:58:51:98:97:f3:bf:8a:9b:b2:c1:b7:0c: + 5f:3f:56:b3:13:3b:d0:80:be:04:66:89:84:50:ca: + fe:f6:f7:6b:05:3b:30:4e:96:9c:5b:c5:80:bc:d6: + be:6e:69:f4:b9:9b:4c:06:7a:ed:37:67:b2:fe:45: + 69:57:62:54:cb:69:69:48:b9:7d:a0:42:f1:b6:dc: + f2:7f:eb:75:2a:d4:83:69:b9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + D9:F3:11:BF:98:5A:60:12:7A:85:B5:E7:A7:38:4F:CF:51:1D:C6:B2 + X509v3 Authority Key Identifier: + keyid:25:A5:90:9F:4D:3A:A4:19:0A:80:46:5E:F3:FB:20:CE:56:30:33:DA + + Signature Algorithm: sha1WithRSAEncryption + 69:6c:26:81:51:91:a6:e6:11:dc:81:35:03:73:85:4f:2f:29: + 1f:20:f2:23:54:82:ca:8f:b8:a6:e3:3f:cd:72:5e:d7:e7:f5: + 84:8a:33:e2:51:9f:36:4b:30:85:f4:4f:87:c7:9a:69:0b:15: + 6e:92:c7:1f:2f:58:a4:57:f8:c2:cd:59:6c:d2:11:63:ae:bb: + b0:32:3f:09:e7:2e:ad:db:1b:fe:e7:a4:21:43:47:76:e1:de: + 36:bb:26:3f:16:76:20:ed:a4:68:c1:48:ae:2b:95:fb:f6:d2: + f2:7f:74:f6:83:e2:89:06:b5:89:54:6e:7f:cf:88:94:66:e8: + da:32 +-----BEGIN CERTIFICATE----- +MIIDPjCCAqegAwIBAgIJAIV94cXZ3nogMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYD +VQQGEwJQTDEUMBIGA1UECBMLTWF6b3dpZWNraWUxEDAOBgNVBAoTB1NhbXN1bmcx +DTALBgNVBAsTBFNQUkMxJzAlBgNVBAMTHk9wZXJhdG9yIFRlc3QgUm9vdCBDZXJ0 +aWZpY2F0ZTEjMCEGCSqGSIb3DQEJARYUb3BlcmF0b3JAc2Ftc3VuZy5jb20wHhcN +MTEwMTA0MTczNDMxWhcNMTIwMTA0MTczNDMxWjCBsTELMAkGA1UEBhMCUEwxFDAS +BgNVBAgTC01hbG9wb2xza2llMQ8wDQYDVQQHEwZLcmFrb3cxEDAOBgNVBAoTB1Nh +bXN1bmcxDDAKBgNVBAsTA04vQTEvMC0GA1UEAxMmT3BlcmF0b3IgVGVzdCBTZWNv +bmQgTGV2ZWwgQ2VydGlmaWNhdGUxKjAoBgkqhkiG9w0BCQEWG3NlY29uZC5vcGVy +YXRvckBzYW1zdW5nLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAujxY +yoceWWhUilQ0Q2HxgeY1wUZ0Fsf/+RWeDFpqicETDGEuugDgcep+Ma5O75NYUZiX +87+Km7LBtwxfP1azEzvQgL4EZomEUMr+9vdrBTswTpacW8WAvNa+bmn0uZtMBnrt +N2ey/kVpV2JUy2lpSLl9oELxttzyf+t1KtSDabkCAwEAAaN7MHkwCQYDVR0TBAIw +ADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUw +HQYDVR0OBBYEFNnzEb+YWmASeoW156c4T89RHcayMB8GA1UdIwQYMBaAFCWlkJ9N +OqQZCoBGXvP7IM5WMDPaMA0GCSqGSIb3DQEBBQUAA4GBAGlsJoFRkabmEdyBNQNz +hU8vKR8g8iNUgsqPuKbjP81yXtfn9YSKM+JRnzZLMIX0T4fHmmkLFW6Sxx8vWKRX ++MLNWWzSEWOuu7AyPwnnLq3bG/7npCFDR3bh3ja7Jj8WdiDtpGjBSK4rlfv20vJ/ +dPaD4okGtYlUbn/PiJRm6Noy +-----END CERTIFICATE----- diff --git a/tests/vcore/test-cases/keys/operator.second.key.pem b/tests/vcore/test-cases/keys/operator.second.key.pem new file mode 100644 index 0000000..ab1214a --- /dev/null +++ b/tests/vcore/test-cases/keys/operator.second.key.pem @@ -0,0 +1,18 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,44C051D8935528BB + +iISuf9ELdyP5M0vlWOK4msH09HRAhN+43qRu/RDznpsTs2lX2sJITXXEmJC4EJzS +Zk4jf3ScTj1JsMGlg5k0mZWLmDb4kUxTRVUqJX2W4uUYEmWav7LQHRAsPwNUSMs3 +DzZabSf1vplnKKoL9mMtX4E0mj79AkJp7tARQu4Zn2FDMg/UnCErzhGeoFysztmM +v0Biyrf8yTbatMMr7Ea6rIsKS8KbkEeYDk4LpxBXkMeOutnnUUdhUEXZ/mwgJq2e ++8LLPiWdFsrGxPdub7iuLXidXSpOd9VaC9LN/ORKF+EiJtF+twWSBotxYOtwmtgj +xUHfXBcbaFoPnLKNS0nxwsOHF07LUfsCHzfVm1uGyWFkkLrPfcSjb6PahFlfO6w5 +fv8HnUOgeAjlhK6X+xhmw1tpwMUlmcYmq31eC8rwxP59jNQbhH6GVr5+rEMRHNgp +loC1WqthoRtBEC0bi99VpIHVIepe9G+p40sIropoUWftfDSLl3RtONg5GyyZWQ4a +ROxsiLHDZ7+q8eKkJuYPkiZ61/5MHuOsH5k57PG7ppG6/0p+ED4bTwxxDb6PU4pA +08xUTZQ0CUn1x80o/lKw+1E9TJOTbCvrEJAnMksfOkNkNyedgDJaxfV63wYvnL4+ +BLzCqa6djpe0Mg2olQieV/piRUt7JaGA7bnaMAn+bJ56PzUnMl0/WlxzGTMtHjkf +zUqgLLdxZpJP7zl4XleSfRWlPgL1iN1s84x48ej+MGgOGi7xTgX/sfCLkN4No/8k +c5Po+lQU261XAYNuAjtjUFQP/FgIMM9CnJrDWp8xHZXUJBo0c5lOKg== +-----END RSA PRIVATE KEY----- diff --git a/tests/vcore/test-cases/keys/operator.second.p12 b/tests/vcore/test-cases/keys/operator.second.p12 new file mode 100644 index 0000000..2add1df Binary files /dev/null and b/tests/vcore/test-cases/keys/operator.second.p12 differ diff --git a/tests/vcore/test-cases/keys/root_cacert0.pem b/tests/vcore/test-cases/keys/root_cacert0.pem new file mode 100644 index 0000000..7aa429f --- /dev/null +++ b/tests/vcore/test-cases/keys/root_cacert0.pem @@ -0,0 +1,64 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + c7:4a:82:f6:9d:1b:f6:7d + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=PL, ST=Maz, O=Samsung, OU=SPRC, CN=Samsung/emailAddress=samsung@samsung.com + Validity + Not Before: Oct 5 11:52:36 2011 GMT + Not After : Oct 4 11:52:36 2014 GMT + Subject: C=PL, ST=Maz, O=Samsung, OU=SPRC, CN=Samsung/emailAddress=samsung@samsung.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:93:c2:12:8b:3e:b1:69:fe:c8:7e:f1:fa:b0:03: + d7:bd:25:03:bb:14:70:ab:65:ff:8f:e9:38:14:2b: + 92:02:d9:e7:b4:78:60:a0:ce:b1:b8:b6:78:c5:af: + b3:83:3c:47:58:3d:1e:a0:78:69:4d:56:dd:8c:d8: + 20:27:b2:0d:9f:bf:f1:d4:e1:39:0f:1b:6f:b8:cd: + ca:f4:0b:fd:d7:cb:64:09:c7:6d:1e:e8:dd:89:43: + 7f:72:85:3d:9a:54:6e:7c:55:a0:da:f5:e9:28:01: + ec:3a:da:5a:18:45:fc:28:b1:0e:43:2c:4c:26:5c: + ca:bc:44:d9:ce:7d:5a:f2:f3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 82:08:7F:DB:00:02:86:E8:53:2A:A5:FA:58:AE:67:7F:14:38:C8:60 + X509v3 Authority Key Identifier: + keyid:82:08:7F:DB:00:02:86:E8:53:2A:A5:FA:58:AE:67:7F:14:38:C8:60 + DirName:/C=PL/ST=Maz/O=Samsung/OU=SPRC/CN=Samsung/emailAddress=samsung@samsung.com + serial:C7:4A:82:F6:9D:1B:F6:7D + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + 0f:cb:a3:cd:25:02:00:17:a9:c5:21:4a:6e:bb:ce:d9:14:74: + 23:29:c5:47:ff:02:91:5a:ee:a1:53:a7:e4:69:6f:f2:00:bc: + 09:87:80:f8:3b:a5:51:59:e9:20:1f:1d:5d:cb:91:eb:91:1e: + f4:79:bf:35:68:a5:ed:24:e5:28:dd:c9:1f:bf:53:f7:75:77: + 6c:fe:94:0c:de:9c:d9:8e:42:c6:7d:61:6b:5d:5d:ad:a7:6a: + e4:9b:53:2a:f7:85:9c:51:1d:72:5d:5c:2f:eb:f9:ff:80:4c: + 6d:46:e8:a0:2c:8a:6f:94:13:b2:00:47:2c:b0:b0:1c:12:fc: + a0:65 +-----BEGIN CERTIFICATE----- +MIIDOjCCAqOgAwIBAgIJAMdKgvadG/Z9MA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV +BAYTAlBMMQwwCgYDVQQIEwNNYXoxEDAOBgNVBAoTB1NhbXN1bmcxDTALBgNVBAsT +BFNQUkMxEDAOBgNVBAMTB1NhbXN1bmcxIjAgBgkqhkiG9w0BCQEWE3NhbXN1bmdA +c2Ftc3VuZy5jb20wHhcNMTExMDA1MTE1MjM2WhcNMTQxMDA0MTE1MjM2WjByMQsw +CQYDVQQGEwJQTDEMMAoGA1UECBMDTWF6MRAwDgYDVQQKEwdTYW1zdW5nMQ0wCwYD +VQQLEwRTUFJDMRAwDgYDVQQDEwdTYW1zdW5nMSIwIAYJKoZIhvcNAQkBFhNzYW1z +dW5nQHNhbXN1bmcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTwhKL +PrFp/sh+8fqwA9e9JQO7FHCrZf+P6TgUK5IC2ee0eGCgzrG4tnjFr7ODPEdYPR6g +eGlNVt2M2CAnsg2fv/HU4TkPG2+4zcr0C/3Xy2QJx20e6N2JQ39yhT2aVG58VaDa +9ekoAew62loYRfwosQ5DLEwmXMq8RNnOfVry8wIDAQABo4HXMIHUMB0GA1UdDgQW +BBSCCH/bAAKG6FMqpfpYrmd/FDjIYDCBpAYDVR0jBIGcMIGZgBSCCH/bAAKG6FMq +pfpYrmd/FDjIYKF2pHQwcjELMAkGA1UEBhMCUEwxDDAKBgNVBAgTA01hejEQMA4G +A1UEChMHU2Ftc3VuZzENMAsGA1UECxMEU1BSQzEQMA4GA1UEAxMHU2Ftc3VuZzEi +MCAGCSqGSIb3DQEJARYTc2Ftc3VuZ0BzYW1zdW5nLmNvbYIJAMdKgvadG/Z9MAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAD8ujzSUCABepxSFKbrvO2RR0 +IynFR/8CkVruoVOn5Glv8gC8CYeA+DulUVnpIB8dXcuR65Ee9Hm/NWil7STlKN3J +H79T93V3bP6UDN6c2Y5Cxn1ha11dradq5JtTKveFnFEdcl1cL+v5/4BMbUbooCyK +b5QTsgBHLLCwHBL8oGU= +-----END CERTIFICATE----- diff --git a/tests/vcore/test-cases/keys/root_cakey0.pem b/tests/vcore/test-cases/keys/root_cakey0.pem new file mode 100644 index 0000000..ff33c13 --- /dev/null +++ b/tests/vcore/test-cases/keys/root_cakey0.pem @@ -0,0 +1,18 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,D2942E015452A445 + +0M/tC+qVDqyhNsxZZB/dGLuNxsStSUA7TRDRiSBee9JsvcFZjq03D/VjBakNIeET +6efmKfAngomfvrWtxhped3RI4vasX05swfnr4qiUKjLPyftmNEepbNGeI8MaiD7a +fEOZuAacstyS5RMHRBXrktq+jtXW2meQTuvEMBJf1AeAIuaFNvr3OvvpCtDwRffi +1ijUVuG0ZQ6MpP7cGeqLYUZ9StTMxeiEesAPM4YrG7HIY13KaHwMr1ZRtENe7qZ8 +R8vwgW188FYkSSrcQjCVEuj/ztTg9eVuSKdTNgjfKzTWnlrjAzi8CKBsrkYoarwS +6Rv3TqVVnx4HHdo9RIUKZPeLOdcMD1OPK7aOUedPTAcht3Y7SQQphBQypLf6PLKB +DCo79B4TUA1W9MijT2d2GN7oJHqHax8zO2j+yCLkEcHF32JZsEFE63Bwss72FXMg +mTmpCwyzR+oN93687JDUBAP9zNVd76ZnpzwlMZirB6QTY/lrH+iXLH3R3PO6cl2R +0Jei4IQ1oB+SX6GOPt4tKGTqktUFhsJYbXyifj4O1ZyDVYTp0JafOLxJfU33oYTm +278yshFdyHRgfKIHvqctZ1xJN2ioVcWf+9DprHc5kGb6wUKRVfQpipTS2hgbMBz+ +UWRZWq+CUD5QkTz4cSQfhPWQF6TNWpTQc0dvAlo3Cmxrro1PriDItsCOeydeNWvn +Dyynx7ODp/F1rX5ekaXkVxsdGgD/HuNF+c7tEytD7U4/CmevytuXRIrFM0alj2OE +aBFTqKicBoKgDV9VUOTKwuFeNV7MSuVDUnngEBeYrinwGa7wuV7tzA== +-----END RSA PRIVATE KEY----- diff --git a/tests/vcore/test-cases/widget/author-signature.xml b/tests/vcore/test-cases/widget/author-signature.xml new file mode 100644 index 0000000..ff82da8 --- /dev/null +++ b/tests/vcore/test-cases/widget/author-signature.xml @@ -0,0 +1,66 @@ + + + + + + + + xUKQbov3HL7JD2/zVUKpPEVGc5C6VWDXwxoDHzDs9y0= + + + + cIE41PzyhMnF++EmhJ3Ptnd4ZqXyBlRJgiIqxlutbV8= + + + + + + + MH34nIMXxv0fMQQ8bTV1wZUNLOrXTmpnxpADlNzmQ/4= + + + fhh+VQq76Uodq4upHhvcC2tgbVY8bL9DiiSe9wn1O4YrIFKMnEEYqYmpQbL1puWU +Zbht0hXpvEFXg1010q5kOZQxknqcyFg3hyVUpFDPARkJs1XhRNbFWJJF7qNXVgt5 +NyFrdXFv4lVFjkv+chSykaWu6V22z43E8kJcg+zGVU8= + + + MIIETTCCA7agAwIBAgIJANaOuOCRgiz3MA0GCSqGSIb3DQEBBQUAMIG8MQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy +aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEeMBwG +A1UECxMVVGVzdCBSb290IENlcnRpZmljYXRlMRYwFAYDVQQDEw1BbGVrc2V5IFNh +bmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5jb20wHhcNMDUwNzEw +MDIyOTAxWhcNMTUwNzA4MDIyOTAxWjCBvDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +CkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1cml0eSBMaWJyYXJ5IChodHRw +Oi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxHjAcBgNVBAsTFVRlc3QgUm9vdCBD +ZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJ +ARYSeG1sc2VjQGFsZWtzZXkuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQDayaFajJxOdVU+8EjwO31S2XqNmYxxbHfiUJO3w2h57OPUkKAcKe5Gvt9hJbPT +b3C4blPScOke2RexKnXS7pAXXbxFlgUlZ0QK0K2pdl559OSmrtH3mPP9BJvvDMlx +kcNj9/EeD+yGd8GN/yT6PTDh8G/4lszOXL+tyKIkC4Ys/wIDAQABo4IBUzCCAU8w +DAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQg +Q2VydGlmaWNhdGUwHQYDVR0OBBYEFNpG6Wvmr9M9quUhS1LtymYo4P6FMIHxBgNV +HSMEgekwgeaAFNpG6Wvmr9M9quUhS1LtymYo4P6FoYHCpIG/MIG8MQswCQYDVQQG +EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3VyaXR5 +IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEeMBwGA1UE +CxMVVGVzdCBSb290IENlcnRpZmljYXRlMRYwFAYDVQQDEw1BbGVrc2V5IFNhbmlu +MSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5jb22CCQDWjrjgkYIs9zAN +BgkqhkiG9w0BAQUFAAOBgQBUXbdOTQwArcNrbxavzARp2JGOnzo6WzTm+OFSXC0F +08YwT8jWbht97e8lNNVOBU4Y/38ReZqYC9OqFofG1/O9AdQ58WL/FWg8DgP5MJPT +T9kRU3FU01jUiX2+kbdnghZAOJm0ziRNxfNPwIIWPKYXyXEKQQzrnxyFey1hP7cg +6A== + + + + + + + + + + + + + + + + diff --git a/tests/vcore/test-cases/widget/config.xml b/tests/vcore/test-cases/widget/config.xml new file mode 100755 index 0000000..82b077b --- /dev/null +++ b/tests/vcore/test-cases/widget/config.xml @@ -0,0 +1,6 @@ + + Widget Name OK + 1.2.3.4 + A short description of widget + Author Name + diff --git a/tests/vcore/test-cases/widget/index.html b/tests/vcore/test-cases/widget/index.html new file mode 100755 index 0000000..c47b20a --- /dev/null +++ b/tests/vcore/test-cases/widget/index.html @@ -0,0 +1,4 @@ + +Not tested + +

None

diff --git a/tests/vcore/test-cases/widget/signature1.xml b/tests/vcore/test-cases/widget/signature1.xml new file mode 100644 index 0000000..71a100b --- /dev/null +++ b/tests/vcore/test-cases/widget/signature1.xml @@ -0,0 +1,62 @@ + + + + + + + + ZLhd8X2rzCIDGHkIvpDbCXq+dwq+DK7ZZaDD/fII8RU= + + + + xUKQbov3HL7JD2/zVUKpPEVGc5C6VWDXwxoDHzDs9y0= + + + + cIE41PzyhMnF++EmhJ3Ptnd4ZqXyBlRJgiIqxlutbV8= + + + + + + + ZxnfFPi1rAoxfpN98xSP3lv5tZg9ymJElAFdg3ejrXE= + + + Dwm15jQbvUxe7fa7p4RVRAUzYY6eGQmDJSWXnv2LBbouch163OMaXgjKXWOLU+ZA +MwwuUUXG44QvOIv5M3Kd/Pc6kwvyb9+xm8zqmFF/mhttmAHc7VjY5sfB+bYFt9/3 +8+upSqxiUGLXYzMD/9u4W9ociwAcLiOQytBF1/TCv/4= + + + MIIC4zCCAkygAwIBAgIJAMdKgvadG/Z+MA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV +BAYTAlBMMQwwCgYDVQQIEwNNYXoxEDAOBgNVBAoTB1NhbXN1bmcxDTALBgNVBAsT +BFNQUkMxEDAOBgNVBAMTB1NhbXN1bmcxIjAgBgkqhkiG9w0BCQEWE3NhbXN1bmdA +c2Ftc3VuZy5jb20wHhcNMTExMDA1MTIwMDUxWhcNMjExMDAyMTIwMDUxWjB4MQsw +CQYDVQQGEwJQTDEMMAoGA1UECBMDTUFaMQwwCgYDVQQHEwNMZWcxDDAKBgNVBAoT +A1NhbTENMAsGA1UECxMEU1BSQzEOMAwGA1UEAxMFRmlsaXAxIDAeBgkqhkiG9w0B +CQEWEWZpbGlwQHNhbXN1bmcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQDS/sS0wXSCb34ojN8bWFd4Pl9eTLHh18UNGsPpLpp4itdfuc/OgyqaSoDwBzVh +EWAVLCTxexUa4Ncva+41NbkW4RCsFzeGs0ktpu1+8Q+v0QEOGqVF2rQkgilzDF/o +O56Fxw9vG1OA+qdQd3yOAV2EqLNBPrEYB9K5GFyffrakSQIDAQABo3sweTAJBgNV +HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp +Y2F0ZTAdBgNVHQ4EFgQUeyy3iV75KtOkpPFd6mnR9dFGZMwwHwYDVR0jBBgwFoAU +ggh/2wAChuhTKqX6WK5nfxQ4yGAwDQYJKoZIhvcNAQEFBQADgYEADtv0CBrQ1QCM +H9jKFjpSpq7zFKMXQeVtb/Zie823//woicg8kxnP5sS4dJWNXNb1iMLdhgV80g1y +t3gTWPxTtFzprQyNiJHTmrbNWXLX1roRVGUE/I8Q4xexqpbNlJIW2Jjm/kqoKfnK +xORG6HNPXZV29NY2fDRPPOIYoFQzrXI= + + + + + + + + + + + + + + + + diff --git a/tests/vcore/test-cases/widget/signature22.xml b/tests/vcore/test-cases/widget/signature22.xml new file mode 100644 index 0000000..715a7cc --- /dev/null +++ b/tests/vcore/test-cases/widget/signature22.xml @@ -0,0 +1,66 @@ + + + + + + + + ZLhd8X2rzCIDGHkIvpDbCXq+dwq+DK7ZZaDD/fII8RU= + + + + xUKQbov3HL7JD2/zVUKpPEVGc5C6VWDXwxoDHzDs9y0= + + + + cIE41PzyhMnF++EmhJ3Ptnd4ZqXyBlRJgiIqxlutbV8= + + + + + + + ZxnfFPi1rAoxfpN98xSP3lv5tZg9ymJElAFdg3ejrXE= + + + fV1J/120GG5L7qsxEkyH6fBvQh2atlpiGMbVM1+pb8Q6pHib5beV6A== + + + MIIEDzCCA3igAwIBAgIJAMdKgvadG/Z/MA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV +BAYTAlBMMQwwCgYDVQQIEwNNYXoxEDAOBgNVBAoTB1NhbXN1bmcxDTALBgNVBAsT +BFNQUkMxEDAOBgNVBAMTB1NhbXN1bmcxIjAgBgkqhkiG9w0BCQEWE3NhbXN1bmdA +c2Ftc3VuZy5jb20wHhcNMTExMDA1MTIxMTMzWhcNMjExMDAyMTIxMTMzWjCBijEL +MAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93aWVja2llMRIwEAYDVQQHEwlsZWdp +b25vd28xEDAOBgNVBAoTB3NhbXN1bmcxDTALBgNVBAsTBHNwcmMxDjAMBgNVBAMT +BW1hZ2RhMSAwHgYJKoZIhvcNAQkBFhFtYWdkYUBzYW1zdW5nLmNvbTCCAbcwggEr +BgcqhkjOOAQBMIIBHgKBgQC1PCOasFhlfMc1yjdcp7zkzXGiW+MpVuFlsdYwkAa9 +sIvNrQLi2ulxcnNBeCHKDbk7U+J3/QwO2XanapQMUqvfjfjL1QQ5Vf7ENUWPNP7c +Evx82Nb5jWdHyRfV//TciBZN8GLNEbfhtWlhI6CbDW1AaY0nPZ879rSIk7/aNKZ3 +FQIVALcr8uQAmnV+3DLIA5nTo0Bg0bjLAoGAJG7meUtQbMulRMdjzeCoya2FXdm+ +4acvInE9/+MybXTB3bFANMyw6WTvk4K9RK8tm52N95cykTjpAbxqTMaXwkdWbOFd +VKAKnyxi/UKtY9Q6NmwJB2hbA1GUzhPko8rEda66CGl0VbyM1lKMJjA+wp9pG110 +L0ov19Q9fvqKp5UDgYUAAoGBAKxAQg7MqCgkC0MJftYjNaKM5n1iZv4j1li49zKf +Y5nTLP+vYAvg0owLNYvJ5ncKfY1DACPU4/+tC7TTua95wgj5rwvAXnzgSyOGuSr0 +fK9DyrH6E0LfXT+WuIQHahm2iSbxqPrChlnp5/EXDTBaO6Qfdpq0BP48ClZebxcA ++TYFo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVy +YXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUmSpShswvWtEABd+l3WxccRcCydUw +HwYDVR0jBBgwFoAUggh/2wAChuhTKqX6WK5nfxQ4yGAwDQYJKoZIhvcNAQEFBQAD +gYEAgfnAu/gMJRC/BFwkgvrHL0TV4ffPVAf7RSnZS6ib4IHGgrvXJvL+Qh7vHykv +ZIqD2L96nY2EaSNr0yXrT81YROndOQUJNx4Y/W8m6asu4hzANNZqWCbApPDIMK6V +cPA1wrKgZqbWp218WBqI2v9pXV0O+jpzxq1+GeQV2UsbRwc= + + + + + + + + + + + + + + + + diff --git a/tests/vcore/vcore_tests.cpp b/tests/vcore/vcore_tests.cpp new file mode 100644 index 0000000..8c66e41 --- /dev/null +++ b/tests/vcore/vcore_tests.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 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 main.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main + */ +#include +#include + +#include // includes headers with g_type_init + +int main (int argc, char *argv[]) +{ + g_type_init(); +// g_thread_init(NULL); + ValidationCore::VCoreInit( + "/usr/share/wrt-engine/fingerprint_list.xml", + "/usr/share/wrt-engine/fingerprint_list.xsd", + "/opt/dbspace/.vcore.db"); + ValidationCore::AttachToThreadRW(); + int status = DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv); + ValidationCore::DetachFromThread(); + ValidationCore::VCoreDeinit(); + + return status; +} + diff --git a/vcore/CMakeLists.txt b/vcore/CMakeLists.txt new file mode 100644 index 0000000..4fdf270 --- /dev/null +++ b/vcore/CMakeLists.txt @@ -0,0 +1,36 @@ +#DB vcore +PKG_CHECK_MODULES(VCORE_DB_DEP + dpl-efl + REQUIRED) + +ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_BINARY_DIR}/vcore/src/database_checksum_vcore.h + COMMAND ${CMAKE_SOURCE_DIR}/vcore/src/orm/gen_db_md5.sh + ARGS ${CMAKE_BINARY_DIR}/vcore/src/database_checksum_vcore.h + ${CMAKE_SOURCE_DIR}/vcore/src/orm/vcore_db + DEPENDS ${CMAKE_SOURCE_DIR}/vcore/src/orm/vcore_db + ${CMAKE_SOURCE_DIR}/vcore/src/orm/gen_db_md5.sh + COMMENT "Generating VCORE database checksum" + ) + +STRING(REPLACE ";" ":" DEPENDENCIES "${VCORE_DB_DEP_INCLUDE_DIRS}") + +ADD_CUSTOM_COMMAND( OUTPUT .cert_svc_vcore.db + COMMAND rm -f ${CMAKE_CURRENT_BINARY_DIR}/.cert_svc_vcore.db + COMMAND CPATH=${DEPENDENCIES} gcc -Wall -include ${CMAKE_BINARY_DIR}/vcore/src/database_checksum_vcore.h -I${PROJECT_SOURCE_DIR}/vcore/src/orm -E ${PROJECT_SOURCE_DIR}/vcore/src/orm/vcore_db_sql_generator.h | grep --invert-match "^#" > ${CMAKE_CURRENT_BINARY_DIR}/cert_svc_vcore_db.sql + COMMAND sqlite3 ${CMAKE_CURRENT_BINARY_DIR}/.cert_svc_vcore.db ".read ${CMAKE_CURRENT_BINARY_DIR}/cert_svc_vcore_db.sql" || rm -f ${CMAKE_CURRENT_BINARY_DIR}/.cert_svc_vcore.db + DEPENDS ${CMAKE_BINARY_DIR}/vcore/src/database_checksum_vcore.h ${PROJECT_SOURCE_DIR}/vcore/src/orm/vcore_db_sql_generator.h ${PROJECT_SOURCE_DIR}/vcore/src/orm/vcore_db + ) + +ADD_CUSTOM_COMMAND( OUTPUT .cert_svc_vcore.db-journal + COMMAND touch + ARGS ${CMAKE_CURRENT_BINARY_DIR}/.cert_svc_vcore.db-journal + ) + +ADD_CUSTOM_TARGET(Sqlite3DbVCORE ALL DEPENDS .cert_svc_vcore.db .cert_svc_vcore.db-journal) + +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/cert_svc_vcore_db.sql + DESTINATION /usr/share/cert-svc/ + ) + +ADD_SUBDIRECTORY(src) diff --git a/vcore/cert_svc_vcore_db.sql b/vcore/cert_svc_vcore_db.sql new file mode 100644 index 0000000..b1254c1 --- /dev/null +++ b/vcore/cert_svc_vcore_db.sql @@ -0,0 +1,27 @@ + + + +PRAGMA foreign_keys = ON; BEGIN TRANSACTION; + + + +CREATE TABLE OCSPResponseStorage ( + cert_chain TEXT not null, + end_entity_check INT , + ocsp_status INT , + next_update_time BIGINT , + PRIMARY KEY(cert_chain, end_entity_check) , + + +CHECK(1) ); + +CREATE TABLE CRLResponseStorage ( + distribution_point TEXT primary key not null, + crl_body TEXT not null, + next_update_time BIGINT , +CHECK(1) ); + +COMMIT; +BEGIN TRANSACTION; CREATE TABLE DB_VERSION_6d8092083d41289ab1c349aeaad617bc (version INT); COMMIT; + + diff --git a/vcore/src/CMakeLists.txt b/vcore/src/CMakeLists.txt new file mode 100644 index 0000000..c9f2308 --- /dev/null +++ b/vcore/src/CMakeLists.txt @@ -0,0 +1,157 @@ +# == customized for cert-svc build script == +SET(API_VERSION ${VERSION_MAJOR}) +# ========================================== + +INCLUDE(FindPkgConfig) + +PKG_CHECK_MODULES(VCORE_DEPS + dpl-efl + dpl-db-efl + ecore + appcore-efl + libxml-2.0 + libsoup-2.4 + libpcre + libpcrecpp + openssl + xmlsec1 + secure-storage + REQUIRED) + +SET(VCORE_DIR + ${PROJECT_SOURCE_DIR}/vcore + ) + +SET(VCORE_SRC_DIR + ${VCORE_DIR}/src/vcore + ) + +SET(VCORE_SOURCES + ${VCORE_SRC_DIR}/api.cpp + ${VCORE_SRC_DIR}/Base64.cpp + ${VCORE_SRC_DIR}/CachedCRL.cpp + ${VCORE_SRC_DIR}/CachedOCSP.cpp + ${VCORE_SRC_DIR}/Certificate.cpp + ${VCORE_SRC_DIR}/CertificateCacheDAO.cpp + ${VCORE_SRC_DIR}/CertificateCollection.cpp + ${VCORE_SRC_DIR}/CertificateConfigReader.cpp + ${VCORE_SRC_DIR}/CertificateLoader.cpp + ${VCORE_SRC_DIR}/CertificateVerifier.cpp + ${VCORE_SRC_DIR}/Config.cpp + ${VCORE_SRC_DIR}/CRL.cpp + ${VCORE_SRC_DIR}/CRLCacheDAO.cpp + ${VCORE_SRC_DIR}/Database.cpp + ${VCORE_SRC_DIR}/DeveloperModeValidator.cpp + ${VCORE_SRC_DIR}/OCSP.cpp + ${VCORE_SRC_DIR}/OCSPCertMgrUtil.cpp + ${VCORE_SRC_DIR}/OCSPUtil.c + ${VCORE_SRC_DIR}/ReferenceValidator.cpp + ${VCORE_SRC_DIR}/RevocationCheckerBase.cpp + ${VCORE_SRC_DIR}/SaxReader.cpp + ${VCORE_SRC_DIR}/SignatureFinder.cpp + ${VCORE_SRC_DIR}/SignatureReader.cpp + ${VCORE_SRC_DIR}/SignatureValidator.cpp + ${VCORE_SRC_DIR}/SoupMessageSendBase.cpp + ${VCORE_SRC_DIR}/SoupMessageSendSync.cpp + ${VCORE_SRC_DIR}/SoupMessageSendAsync.cpp + ${VCORE_SRC_DIR}/VerificationStatus.cpp + ${VCORE_SRC_DIR}/ValidatorFactories.cpp + ${VCORE_SRC_DIR}/VCore.cpp + ${VCORE_SRC_DIR}/XmlsecAdapter.cpp + ${VCORE_SRC_DIR}/pkcs12.c + ) + +SET(VCORE_INCLUDES + ${VCORE_DEPS_INCLUDE_DIRS} + ${VCORE_SRC_DIR} + ${VCORE_DIR}/src + ${VCORE_DIR}/src/orm + ${VCORE_DIR}/src/legacy + ${CMAKE_BINARY_DIR}/vcore/src + ) + +ADD_DEFINITIONS(${VCORE_DEPS_CFLAGS}) +ADD_DEFINITIONS(${VCORE_DEPS_CFLAGS_OTHER}) +ADD_DEFINITIONS("-DSEPARATED_SINGLETON_IMPLEMENTATION") +ADD_DEFINITIONS("-DDPL_LOGS_ENABLED") + +INCLUDE_DIRECTORIES(${VCORE_INCLUDES}) + +# cert-svc headers +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) + +ADD_LIBRARY(${TARGET_VCORE_LIB} SHARED ${VCORE_SOURCES}) +SET_TARGET_PROPERTIES(${TARGET_VCORE_LIB} PROPERTIES + SOVERSION ${API_VERSION} + VERSION ${VERSION}) + +ADD_DEPENDENCIES(${TARGET_VCORE_LIB} Sqlite3DbWTF) + +SET_TARGET_PROPERTIES(${TARGET_VCORE_LIB} PROPERTIES + COMPILE_FLAGS -fPIC) + +TARGET_LINK_LIBRARIES(${TARGET_VCORE_LIB} + ${VCORE_DEPS_LIBRARIES} + cert-svc + ) + +INSTALL(TARGETS ${TARGET_VCORE_LIB} + DESTINATION /usr/lib + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ + ) + +INSTALL(FILES + ${VCORE_SRC_DIR}/Base64.h + ${VCORE_SRC_DIR}/CachedCRL.h + ${VCORE_SRC_DIR}/CachedOCSP.h + ${VCORE_SRC_DIR}/Certificate.h + ${VCORE_SRC_DIR}/CertificateCacheDAO.h + ${VCORE_SRC_DIR}/CertificateCollection.h + ${VCORE_SRC_DIR}/CertificateConfigReader.h + ${VCORE_SRC_DIR}/CertificateLoader.h + ${VCORE_SRC_DIR}/CertificateStorage.h + ${VCORE_SRC_DIR}/CertificateVerifier.h + ${VCORE_SRC_DIR}/CertStoreType.h + ${VCORE_SRC_DIR}/Config.h + ${VCORE_SRC_DIR}/CRL.h + ${VCORE_SRC_DIR}/Database.h + ${VCORE_SRC_DIR}/DeveloperModeValidator.h + ${VCORE_SRC_DIR}/IAbstractResponseCache.h + ${VCORE_SRC_DIR}/OCSP.h + ${VCORE_SRC_DIR}/OCSPCertMgrUtil.h + ${VCORE_SRC_DIR}/ParserSchema.h + ${VCORE_SRC_DIR}/ReferenceValidator.h + ${VCORE_SRC_DIR}/RevocationCheckerBase.h + ${VCORE_SRC_DIR}/SaxReader.h + ${VCORE_SRC_DIR}/scoped_gpointer.h + ${VCORE_SRC_DIR}/SignatureData.h + ${VCORE_SRC_DIR}/SignatureFinder.h + ${VCORE_SRC_DIR}/SignatureReader.h + ${VCORE_SRC_DIR}/SignatureValidator.h + ${VCORE_SRC_DIR}/SoupMessageSendBase.h + ${VCORE_SRC_DIR}/SoupMessageSendSync.h + ${VCORE_SRC_DIR}/SoupMessageSendAsync.h + ${VCORE_SRC_DIR}/SSLContainers.h + ${VCORE_SRC_DIR}/VerificationStatus.h + ${VCORE_SRC_DIR}/ValidatorCommon.h + ${VCORE_SRC_DIR}/ValidatorFactories.h + ${VCORE_SRC_DIR}/VCore.h + ${VCORE_SRC_DIR}/XmlsecAdapter.h + DESTINATION /usr/include/cert-svc/vcore + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ + ) + +INSTALL(FILES + ${VCORE_DIR}/src/cert-svc/ccert.h + ${VCORE_DIR}/src/cert-svc/ccrl.h + ${VCORE_DIR}/src/cert-svc/cinstance.h + ${VCORE_DIR}/src/cert-svc/cerror.h + ${VCORE_DIR}/src/cert-svc/cocsp.h + ${VCORE_DIR}/src/cert-svc/cpkcs12.h + ${VCORE_DIR}/src/cert-svc/cprimitives.h + ${VCORE_DIR}/src/cert-svc/cstring.h + DESTINATION /usr/include/cert-svc/cert-svc + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ + ) + +#FILE(MAKE_DIRECTORY /opt/share/cert-svc/pkcs12) diff --git a/vcore/src/cert-svc/ccert.h b/vcore/src/cert-svc/ccert.h new file mode 100644 index 0000000..865c301 --- /dev/null +++ b/vcore/src/cert-svc/ccert.h @@ -0,0 +1,324 @@ +/** + * Copyright (c) 2011 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 ccert.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This is part of C api for ValidationCore. + */ +#ifndef _CERTSVC_CCERT_H_ +#define _CERTSVC_CCERT_H_ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct CertSvcCertificate_t { + int privateHandler; + CertSvcInstance privateInstance; +} CertSvcCertificate; + +typedef struct CertSvcCertificateList_t { + int privateHandler; + CertSvcInstance privateInstance; +} CertSvcCertificateList; + +typedef enum CertSvcCertificateForm_t { +/* CERTSVC_FORM_PEM, */ + CERTSVC_FORM_DER, + CERTSVC_FORM_DER_BASE64 +} CertSvcCertificateForm; + +typedef enum CertSvcCertificateField_t { + CERTSVC_SUBJECT, + CERTSVC_SUBJECT_COMMON_NAME, + CERTSVC_SUBJECT_COUNTRY_NAME, + CERTSVC_SUBJECT_STATE_NAME, + CERTSVC_SUBJECT_ORGANIZATION_NAME, + CERTSVC_SUBJECT_ORGANIZATION_UNIT_NAME, + CERTSVC_ISSUER, + CERTSVC_ISSUER_COMMON_NAME, + CERTSVC_ISSUER_COUNTRY_NAME, + CERTSVC_ISSUER_STATE_NAME, + CERTSVC_ISSUER_ORGANIZATION_NAME, + CERTSVC_ISSUER_ORGANIZATION_UNIT_NAME, + CERTSVC_VERSION, + CERTSVC_SERIAL_NUMBER, + CERTSVC_KEY_USAGE, + CERTSVC_KEY, + CERTSVC_SIGNATURE_ALGORITHM +} CertSvcCertificateField; + +/** + * Read certificate from file. Certificate must be in PEM/CER/DER format. + * + * @param[in] instance CertSvcInstance object. + * @param[in] location Path to file with certificate file. + * @param[out] certificate Certificate id assigned to loaded certificate. + * @return CERTSVC_SUCCESS, CERTSVC_BAD_ALLOC, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_certificate_new_from_file(CertSvcInstance instance, + const char *location, + CertSvcCertificate *certificate); + +/** + * Read certificate stored in memory. + * + * @param[in] instance CertSvcInstance object. + * @param[in] memory Pointer to memory with certificate data. + * @param[in] len Size of certificate. + * @param[in] form Certificate format. + * @param[out] certificate Certificate id assigned to loaded certificate. + * @return CERTSVC_SUCCESS, CERTSVC_BAD_ALLOC, CERTSVC_FAIL + */ +int certsvc_certificate_new_from_memory(CertSvcInstance instance, + const unsigned char *memory, + int len, + CertSvcCertificateForm form, + CertSvcCertificate *certificate); + +/** + * Free structures connected with certificate. + * + * @param[in] certificate Certificate id. + */ +void certsvc_certificate_free(CertSvcCertificate certificate); + +/** + * Save certificate to file. It saves certificate in DER format. + * + * @param[in] certificate Certificate id. + * @param[in] location Path to file. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_certificate_save_file(CertSvcCertificate certificate, const char *location); + +/** + * Search certificate with specific data. Result is stored in CertSvcInstance. + * This function will erase all preverious results stored in CertSvcInstance but + * it will not erase any CertSvcCertificate. + * + * You can search by fields: CERTSVC_SUBJECT, CERTSVC_ISSUER, CERTSVC_SUBJECT_COMMON_NAME + * + * @param[in] instance CertSvcInstance object. + * @param[in] field Certificate filed name. + * @param[in] value Value to search for. + * @param[out] handler Handler to search result. + * @return CERTSVC_SUCCESS, CERTSVC_BAD_ALLOC, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_certificate_search(CertSvcInstance instance, + CertSvcCertificateField field, + const char *value, + CertSvcCertificateList *handler); + +/** + * This function will return certificate id founded by certsvc_certificate_search. + * You can call this function multiple times to get all results. + * + * @param[in] hadler Hander to search results. + * @param[in] position + * @param[out] certificate Certficate id. + * @return CERTSVC_SUCCESS, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_certificate_list_get_one(CertSvcCertificateList handler, + int position, + CertSvcCertificate *certificate); + +/** + * Return number of elements on the list. + * + * @param[in] handler Handler to certifiacte list. + * @param[out] length Size of list. + * @return CERTSVC_SUCCESS, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_certificate_list_get_length(CertSvcCertificateList handler, + int *size); + +/** + * This function will free list. It will not free certificates on the list. + * You may free each certificate with certsvc_certificate_free. + * + * @param[in] handler Handler to search result. + */ +void certsvc_certificate_list_free(CertSvcCertificateList handler); + +/** + * Compare parent certificate subject with child issuer field. + * + * @param[in] child + * @param[in] parent + * @param[out] status CERTSVC_TRUE if "signer" was used to sign "child" certificate in other cases it will return CERTSVC_FALSE. + * @return CERTSVC_SUCCESS, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_certificate_is_signed_by(CertSvcCertificate child, + CertSvcCertificate parent, + int *status); + +/** + * Extract specific data from certificate. Data in buffer could be free + * by certsvc_free_string function or by + * certsvc_instance_free or vcore_instance_reset. + * + * @param[in] certificate Certificate id. + * @param[in] field Type of data to extract. + * @param[out] buffer Extracted data. + * return CERTSVC_SUCCESS, CERTSVC_BAD_ALLOC, CERTSVC_FAIL + */ +int certsvc_certificate_get_string_field(CertSvcCertificate certificate, + CertSvcCertificateField field, + CertSvcString *buffer); + +/** + * Extract NOT AFTER data from certificate. + * + * @param[in] certificate Certificate id. + * @param[out] result date + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_certificate_get_not_after(CertSvcCertificate certificate, time_t *result); + +/** + * Extract NOT AFTER data from certificate. + * + * @param[in] certificate Certificate id. + * @param[out] result date + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_certificate_get_not_before(CertSvcCertificate certificate, time_t *result); + +/** + * Check certificate. This fuction compares SUBJECT and ISSUER fields. + * TODO: This fuction should also check ROOTCA field in certificate. + * + * @param[in] certificate Certificate id. + * @param[out] status CERTSVC_TRUE or CERTSVC_FALSE + * @return CERTSVC_SUCCESS, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_certificate_is_root_ca(CertSvcCertificate certificate, int *status); + +/** + * Extract all distribution point from certificate. + * + * @param[in] certificate Certificate with distribution points. + * @param[out] hander Handler to set of string. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + * + * Usage example: + * + * int max; + * CertSvcStringList handler; + * certsvc_certificate_get_crl_distribution_points(instance, some_certificate, &handler); + * certsvc_certificate_list_get_length(handler, &max); + * for(int i=0; i + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CERTSVC_CRL_GOOD (1<<0) +#define CERTSVC_CRL_REVOKED (1<<1) +#define CERTSVC_CRL_VERIFICATION_ERROR (1<<3) +#define CERTSVC_CRL_NO_SUPPORT (1<<4) + +typedef void (*CertSvcCrlCacheWrite)( + const char *distributionPoint, + const char *body, + int bodySize, + time_t nextUpdateTime, + void *userParam); + +typedef int (*CertSvcCrlCacheRead)( + const char *distributionPoint, + char **body, + int *bodySize, + time_t *nextUpdateTime, + void *userParam); + +typedef void (*CertSvcCrlFree)( + char *buffer, + void *userParam); + +void certsvc_crl_cache_functions( + CertSvcInstance instance, + CertSvcCrlCacheWrite writePtr, + CertSvcCrlCacheRead readPtr, + CertSvcCrlFree freePtr); + +int certsvc_crl_check( + CertSvcCertificate certificate, + CertSvcCertificate *trustedStore, + int storeSize, + int force, + int *status, + void *userParam); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/vcore/src/cert-svc/cerror.h b/vcore/src/cert-svc/cerror.h new file mode 100644 index 0000000..0566152 --- /dev/null +++ b/vcore/src/cert-svc/cerror.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2011 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 cerror.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This is part of C api for ValidationCore. + */ + +#ifndef _CERTSVC_CERROR_H_ +#define _CERTSVC_CERROR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define CERTSVC_TRUE (1) +#define CERTSVC_FALSE (0) + +#define CERTSVC_SUCCESS (1) +#define CERTSVC_FAIL (0) /* Openssl internal error. */ +#define CERTSVC_BAD_ALLOC (-2) /* Memmory allcation error. */ +//#define CERTSVC_FILE_NOT_FOUND (-3) /* Certificate file does not exists. */ +#define CERTSVC_WRONG_ARGUMENT (-4) /* Function argumnet is wrong. */ +#define CERTSVC_INVALID_ALGORITHM (-5) /* Algorithm is not supported. */ +#define CERTSVC_INVALID_SIGNATURE (-6) /* Signature and message does not match. */ +#define CERTSVC_IO_ERROR (-7) /* Certificate file IO error. */ +#define CERTSVC_INVALID_PASSWORD (-8) /* Certificate container password mismatch. */ +#define CERTSVC_DUPLICATED_ALIAS (-9) /* User-provided alias is aleady taken. */ + +#ifdef __cplusplus +} +#endif + +#endif // _CERTSVC_CERROR_H_ diff --git a/vcore/src/cert-svc/cinstance.h b/vcore/src/cert-svc/cinstance.h new file mode 100644 index 0000000..93ee23d --- /dev/null +++ b/vcore/src/cert-svc/cinstance.h @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2011 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 cinstance.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This is part of C api for ValidationCore. + */ +#ifndef _CERTSVC_CINSTANCE_H_ +#define _CERTSVC_CINSTANCE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct CertSvcInstance_t { + void *privatePtr; +} CertSvcInstance; + +/** + * Allocate internal data of CertSvc library and put it in the CertSvcInstance structure. + * Initialize Openssl interanal structures, initialize all structures required by libsoup + * (libsoup is used by ocps and crl functions). + * + * @param[out] instance Pointer to CertSvcInstance. + * @return CERTSVC_SUCCESS or CERTSVC_FAIL. + */ +int certsvc_instance_new(CertSvcInstance *instance); + +/** + * This function will free all allocated data. All certificate identificator will + * be released and all strings allocated by certsvc_certificate_get_string field will be + * released also. + * + * This fucntion does not release CertSvcInstnace! + * + * Plese note: It is safe to use this function after use certsvc_string_free. + * + * @param[in] instance CertSvcInstance object. + */ +void certsvc_instance_reset(CertSvcInstance instance); + +/** + * This function will free all allocated data. All certificate identificator will + * be released and all strings allocated by certsvc_certificate_get_string field will be + * released also. + * + * This fucntion also release CertSvcInstnace! + * + * Please note: It is safe use this function after use certsvc_string_free. + * + * @param[in] instance CertSvcInstance object + */ +void certsvc_instance_free(CertSvcInstance instance); + +#ifdef __cplusplus +} +#endif + +#endif // _CERTSVC_CINSTANCE_H_ + diff --git a/vcore/src/cert-svc/cocsp.h b/vcore/src/cert-svc/cocsp.h new file mode 100644 index 0000000..da37d2b --- /dev/null +++ b/vcore/src/cert-svc/cocsp.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2011 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 cocsp.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This is C api for ValidationCore. + */ +#ifndef _CERTSVC_OCSP_C_API_H_ +#define _CERTSVC_OCSP_C_API_H_ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CERTSVC_OCSP_GOOD (1<<0) +#define CERTSVC_OCSP_REVOKED (1<<1) +#define CERTSVC_OCSP_UNKNOWN (1<<2) +#define CERTSVC_OCSP_VERIFICATION_ERROR (1<<3) +#define CERTSVC_OCSP_NO_SUPPORT (1<<4) +#define CERTSVC_OCSP_ERROR (1<<5) + +/** + * Implementation of ocsp call. + * + * Please note: to verify certificate you need certificate and his parrent. + * This function will always verify chain_size-1 certificates from the chain. + * + * @param[in] chain Certificate to check. + * @param[in] chain_size Size of certificate_array + * @param[in] trusted Store with trusted certificates (additional certificates + * that may by reqired during verification process). + * @param[in] trusted_size Size of trusted certificate store. + * @param[in] url Force OCSP to use specific server. Pass NULL to use OCSP server defined in certificate. + * @param[out] status Bit field with description of chain validation. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_ocsp_check(CertSvcCertificate *chain, + int chainSize, + CertSvcCertificate *trusted, + int truestedSize, + const char *url, + int *status); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vcore/src/cert-svc/cpkcs12.h b/vcore/src/cert-svc/cpkcs12.h new file mode 100644 index 0000000..878f37b --- /dev/null +++ b/vcore/src/cert-svc/cpkcs12.h @@ -0,0 +1,133 @@ +/** + * Copyright (c) 2011 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 cpkcs12.h + * @author Jacek Migacz (j.migacz@samsung.com) + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @brief This is part of C api for PKCS#12/PFX storage routines. + */ +#ifndef _CERTSVC_CPKCS12_H_ +#define _CERTSVC_CPKCS12_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Query PKCS#12 storage to find out whenever new alias proposal is unique. + * + * @param[in] instance CertSvcInstance object. + * @param[in] proposal Desired alias name. + * @param[out] is_unique CERTSVC_TRUE (if there isn't such alias already) or CERTSVC_FALSE. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_pkcs12_alias_exists(CertSvcInstance instance, + CertSvcString alias, + int *is_unique); + +/** + * Import PKCS#12 container from file. + * + * @param[in] instance CertSvcInstance object. + * @param[in] path Path to container file. + * @param[in] password Container password (can be empty or NULL). + * @param[in] alias Logical name for certificate bundle idenification (can't be empty). + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_INVALID_PASSWORD, CERTSVC_WRONG_ARGUMENT, CERTSVC_DUPLICATED_ALIAS + */ +int certsvc_pkcs12_import_from_file(CertSvcInstance instance, + CertSvcString path, + CertSvcString password, + CertSvcString alias); + +/** + * Get a list of PKCS#12 bundles from storage. This list could be freed by: + * certsvc_string_list_free, certsvc_instance_reset, certsvc_instance_free. + * + * @param[in] instance CertSvcInstance object. + * @param[out] pfxIdStringList List of PKCS#12 aliases. + * @return CERTSVC_SUCCESS, CERTSVC_BAD_ALLOC, CERTSVC_FAIL + */ +int certsvc_pkcs12_get_id_list(CertSvcInstance instance, + CertSvcStringList *pfxIdStringList); + +/** + * Check whenever PKCS#12 container is password protected. + * + * @param[in] instance CertSvcInstance object. + * @param[in] path Path to container file. + * @param[out] has_password CERTSVC_TRUE (if container is password protected) or CERTSVC_FALSE. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_pkcs12_has_password(CertSvcInstance instance, + CertSvcString filepath, + int *has_password); + +/** + * Get a list of certificates from PKCS#12 bundle. You may free this list by: + * certsvc_certificate_list_free. You may free certificates from list with: + * certsvc_certificate_free. + * + * @param[in] instance CertSvcInstance object. + * @param[in] pfxIdString Identification of pfx/pkcs file. + * @param[out] certificateList List of certificates. + * @return CERTSVC_SUCCESS, CERTSVC_BAD_ALLOC, CERTSVC_FAIL, CERTSVC_IO_ERROR + */ +int certsvc_pkcs12_load_certificate_list(CertSvcInstance instance, + CertSvcString alias, + CertSvcCertificateList* certificateList); + +/** + * This function will load to memory private file content. This functin will + * not parse it in any way. + * This memory must be freed by certsvc_private_key_free. + * + * @param[in] instance CertSvcInstance object. + * @param[in] prfIdString Container bundle identifier. + * @param[out] buffer Poiner to newly-allocated memory with private key data. + * @param[out] size Size of the newly-allocated buffer. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_pkcs12_private_key_dup(CertSvcInstance instance, + CertSvcString alias, + char **buffer, + int *size); + +/** + * Couter-routine for certsvc_pkcs12_private_key_dup. + * + * @param[in] pointer Memory claimed by private key. + */ +void certsvc_pkcs12_private_key_free(char *buffer); + +/** + * Remove logical PKCS#12 container with associated certificates and private key. + * + * @param[in] instance CertSvcInstance object. + * @param[in] alias Container bundle identifier. + * @return CERTSVC_SUCCESS, CERTSVC_IO_ERROR, CERTSVC_BAD_ALLOC + */ +int certsvc_pkcs12_delete(CertSvcInstance instance, + CertSvcString alias); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vcore/src/cert-svc/cprimitives.h b/vcore/src/cert-svc/cprimitives.h new file mode 100644 index 0000000..420ae15 --- /dev/null +++ b/vcore/src/cert-svc/cprimitives.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2011 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 vcore_api_extension.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This is C api for ValidationCore. + */ +#ifndef _CERTSVC_C_API_EXTENDED_H_ +#define _CERTSVC_C_API_EXTENDED_H_ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This will return X509 struct(openssl base struct). This struct must be release by function + * certsvc_certificate_free_x509. + * + * vcore_instance_free or vcore_instance_reset will not free memory allocated by this function! + * + * @param[in] certificate Pointer to certificate. + * @param[out] cert Duplicate of certificate. + * @return X509 CERTSVC_SUCCESS, CERTSVC_WRONG_ARGUMENT, CERTSVC_FAIL + */ +int certsvc_certificate_dup_x509(CertSvcCertificate certificate, X509** cert); + +/** + * Release X509 struct allocated by certsvc_certificate_new_x509_copy function. + * + * @param[in] x509_copy Pointer to openssl struct. + */ +void certsvc_certificate_free_x509(X509 *x509_copy); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vcore/src/cert-svc/cstring.h b/vcore/src/cert-svc/cstring.h new file mode 100644 index 0000000..736e9d2 --- /dev/null +++ b/vcore/src/cert-svc/cstring.h @@ -0,0 +1,129 @@ +/** + * Copyright (c) 2011 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 cstring.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This is part of C api for ValidationCore. + */ +#ifndef _CERTSVC_CSTRING_H_ +#define _CERTSVC_CSTRING_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct CertSvcStringList_t { + int privateHandler; + CertSvcInstance privateInstance; +} CertSvcStringList; + +typedef struct CertSvcString_t { + char* privateHandler; + int privateLength; + CertSvcInstance privateInstance; +} CertSvcString; + +/** + * This function will duplicate input data. Data in ouput string will be managed by certsvc. + * + * @param[in] instance CertSvcString will be conected with this instance. + * @param[in] input Input data. + * @param[in] size Input buffer size. + * @param[out] output Buffer with output data. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_string_new( + CertSvcInstance instance, + const char *input, + int size, + CertSvcString *output); + +/** + * This function wont duplicate input data. Output param will contain pointer to input + * so input could not be free as long as ouput param is used. + * + * @param[in] instance CertSvcString will be conected with this instance. + * @param[in] input Input data. + * @param[in] size Input buffer size. + * @param[out] output Buffer with output data. + * @return CERTSVC_SUCCESS, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_string_not_managed( + CertSvcInstance instance, + const char *input, + int size, + CertSvcString *output); + +/** + * Extract next result from result set. Function certsvc_string_list_free + * does not free results returned by this function. CertSvcString is valid + * until certsvc_string_free or vcore_instance_reset or vcore_instance_free + * is called. + * + * @param[in] handler Handler to set of strings. + * @param[out] buffer The buffer will be pointing to string with distrubution point url or will be set to NULL if error occures. + * @param[out] size Size of data pointed by buffer or 0 if error occures. + * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_WRONG_ARGUMENT, CERTSVC_BAD_ALLOC + */ +int certsvc_string_list_get_one(CertSvcStringList hander, + int position, + CertSvcString *buffer); + +/** + * Extract CertSvcStringList size. + * + * @param[in] handler Handler to string list. + * @param[out] size Number of elements on the list. + * @return CERTSVC_SUCCESS, CERTSVC_WRONG_ARGUMENT + */ +int certsvc_string_list_get_length(CertSvcStringList hander,int *size); + +/** + * Free data. + * + * @param[in] string Data allocated by certsvc_certificate_get_string_field + */ +void certsvc_string_free(CertSvcString string); + +/** + * Free string list. + * + * Note: This function does not free strings returned by certsvc_string_list_get_one_result. + * + * @param[in] handler String set handler. + */ +void certsvc_string_list_free(CertSvcStringList handler); + +/** + * Convert CertSvcStringPtr into pure c pointer. Please note that this pointer is valid as long as CertSvcString is valid. + * + * @param[in] string CertSvcStringPtr. + * @param[out] buffer cstring + * @param[out] len Length of cstring + */ +void certsvc_string_to_cstring(CertSvcString string, const char **buffer, int *len); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/vcore/src/orm/DESCRIPTION b/vcore/src/orm/DESCRIPTION new file mode 100644 index 0000000..7d25d0d --- /dev/null +++ b/vcore/src/orm/DESCRIPTION @@ -0,0 +1 @@ +Scripts required to create vcoredatabase. diff --git a/vcore/src/orm/gen_db_md5.sh b/vcore/src/orm/gen_db_md5.sh new file mode 100755 index 0000000..a81d5f7 --- /dev/null +++ b/vcore/src/orm/gen_db_md5.sh @@ -0,0 +1,5 @@ +#!/bin/sh +CHECKSUM=`cat ${2} ${3} 2>/dev/null | md5sum 2>/dev/null | cut -d\ -f1 2>/dev/null` +echo "#define DB_CHECKSUM DB_VERSION_${CHECKSUM}" > ${1} +echo "#define DB_CHECKSUM_STR \"DB_VERSION_${CHECKSUM}\"" >> ${1} + diff --git a/vcore/src/orm/orm_generator_vcore.h b/vcore/src/orm/orm_generator_vcore.h new file mode 100644 index 0000000..862bc80 --- /dev/null +++ b/vcore/src/orm/orm_generator_vcore.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 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. + */ + +#ifndef ORM_GENERATOR_VCORE_H +#define ORM_GENERATOR_VCORE_H + +#define ORM_GENERATOR_DATABASE_NAME vcore_db_definitions +#include +#undef ORM_GENERATOR_DATABASE_NAME + +#endif // ORM_GENERATOR_VCORE_H diff --git a/vcore/src/orm/vcore_db b/vcore/src/orm/vcore_db new file mode 100644 index 0000000..6947255 --- /dev/null +++ b/vcore/src/orm/vcore_db @@ -0,0 +1,23 @@ +SQL( + PRAGMA foreign_keys = ON; + BEGIN TRANSACTION; +) +CREATE_TABLE(OCSPResponseStorage) + COLUMN_NOT_NULL(cert_chain, TEXT,) + COLUMN(end_entity_check, INT,) + COLUMN(ocsp_status, INT,) + COLUMN(next_update_time, BIGINT,) + TABLE_CONSTRAINTS( + PRIMARY KEY(cert_chain, end_entity_check) + ) +CREATE_TABLE_END() + +CREATE_TABLE(CRLResponseStorage) + COLUMN_NOT_NULL(distribution_point,TEXT, primary key) + COLUMN_NOT_NULL(crl_body, TEXT,) + COLUMN(next_update_time, BIGINT,) +CREATE_TABLE_END() + +SQL( + COMMIT; +) diff --git a/vcore/src/orm/vcore_db_definitions b/vcore/src/orm/vcore_db_definitions new file mode 100644 index 0000000..61018c4 --- /dev/null +++ b/vcore/src/orm/vcore_db_definitions @@ -0,0 +1,6 @@ +DATABASE_START(vcore) + +#include "vcore_db" +#include "version_db" + +DATABASE_END() diff --git a/vcore/src/orm/vcore_db_sql_generator.h b/vcore/src/orm/vcore_db_sql_generator.h new file mode 100644 index 0000000..76f0448 --- /dev/null +++ b/vcore/src/orm/vcore_db_sql_generator.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011 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. + */ + +//Do not include this file directly! It is used only for SQL code generation. + +#include + +#include "vcore_db_definitions" diff --git a/vcore/src/orm/version_db b/vcore/src/orm/version_db new file mode 100644 index 0000000..7e20d8d --- /dev/null +++ b/vcore/src/orm/version_db @@ -0,0 +1,5 @@ +SQL( + BEGIN TRANSACTION; + CREATE TABLE DB_CHECKSUM (version INT); + COMMIT; +) diff --git a/vcore/src/vcore/Base64.cpp b/vcore/src/vcore/Base64.cpp new file mode 100644 index 0000000..b772178 --- /dev/null +++ b/vcore/src/vcore/Base64.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2011 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. + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "Base64.h" + +namespace ValidationCore { +Base64Encoder::Base64Encoder() : + m_b64(0), + m_bmem(0), + m_finalized(false) +{ +} + +void Base64Encoder::append(const std::string &data) +{ + if (m_finalized) { + LogWarning("Already finalized."); + ThrowMsg(Exception::AlreadyFinalized, "Already finalized"); + } + + if (!m_b64) { + reset(); + } + BIO_write(m_b64, data.c_str(), data.size()); +} + +void Base64Encoder::finalize() +{ + if (m_finalized) { + LogWarning("Already finalized."); + ThrowMsg(Exception::AlreadyFinalized, "Already finalized."); + } + m_finalized = true; + BIO_flush(m_b64); +} + +std::string Base64Encoder::get() +{ + if (!m_finalized) { + LogWarning("Not finalized"); + ThrowMsg(Exception::NotFinalized, "Not finalized"); + } + BUF_MEM *bptr = 0; + BIO_get_mem_ptr(m_b64, &bptr); + if (bptr == 0) { + LogError("Bio internal error"); + ThrowMsg(Exception::InternalError, "Bio internal error"); + } + + if (bptr->length > 0) { + return std::string(bptr->data, bptr->length - 1); + } + return std::string(); +} + +void Base64Encoder::reset() +{ + m_finalized = false; + BIO_free_all(m_b64); + m_b64 = BIO_new(BIO_f_base64()); + m_bmem = BIO_new(BIO_s_mem()); + if (!m_b64 || !m_bmem) { + LogError("Error during allocation memory in BIO"); + ThrowMsg(Exception::InternalError, + "Error during allocation memory in BIO"); + } + m_b64 = BIO_push(m_b64, m_bmem); +} + +Base64Encoder::~Base64Encoder() +{ + BIO_free_all(m_b64); +} + +Base64Decoder::Base64Decoder() : + m_finalized(false) +{ +} + +void Base64Decoder::append(const std::string &data) +{ + if (m_finalized) { + LogWarning("Already finalized."); + ThrowMsg(Exception::AlreadyFinalized, "Already finalized."); + } + m_input.append(data); +} + +static bool whiteCharacter(char a) +{ + if (a == '\n') { return true; } + return false; +} + +bool Base64Decoder::finalize() +{ + if (m_finalized) { + LogWarning("Already finalized."); + ThrowMsg(Exception::AlreadyFinalized, "Already finalized."); + } + + m_finalized = true; + + m_input.erase(std::remove_if(m_input.begin(), + m_input.end(), + whiteCharacter), + m_input.end()); + + for (size_t i = 0; i tmp(strdup(m_input.c_str())); + m_input.clear(); + + bmem = BIO_new_mem_buf(tmp.Get(), len); + + if (!bmem) { + BIO_free(b64); + LogError("Internal error in BIO"); + ThrowMsg(Exception::InternalError, "Internal error in BIO"); + } + + bmem = BIO_push(b64, bmem); + + if (!bmem) { + BIO_free(b64); + LogError("Internal error in BIO"); + ThrowMsg(Exception::InternalError, "Internal error in BIO"); + } + + int readlen = BIO_read(bmem, buffer.Get(), len); + m_output.clear(); + + bool status = true; + + if (readlen > 0) { + m_output.append(buffer.Get(), readlen); + } else { + status = false; + } + + BIO_free_all(bmem); + return status; +} + +std::string Base64Decoder::get() const +{ + if (!m_finalized) { + LogWarning("Not finalized."); + ThrowMsg(Exception::NotFinalized, "Not finalized"); + } + return m_output; +} + +void Base64Decoder::reset() +{ + m_finalized = false; + m_input.clear(); + m_output.clear(); +} +} // namespace ValidationCore diff --git a/vcore/src/vcore/Base64.h b/vcore/src/vcore/Base64.h new file mode 100644 index 0000000..520662e --- /dev/null +++ b/vcore/src/vcore/Base64.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2011 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. + */ +#ifndef _BASE64_H_ +#define _BASE64_H_ + +#include +#include +#include + +struct bio_st; +typedef bio_st BIO; + +namespace ValidationCore { +class Base64Encoder : public DPL::Noncopyable +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, InternalError) + DECLARE_EXCEPTION_TYPE(Base, NotFinalized) + DECLARE_EXCEPTION_TYPE(Base, AlreadyFinalized) + }; + Base64Encoder(); + void append(const std::string &data); + void finalize(); + std::string get(); + void reset(); + ~Base64Encoder(); + + private: + BIO *m_b64; + BIO *m_bmem; + bool m_finalized; +}; + +class Base64Decoder : public DPL::Noncopyable +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, InternalError) + DECLARE_EXCEPTION_TYPE(Base, NotFinalized) + DECLARE_EXCEPTION_TYPE(Base, AlreadyFinalized) + }; + Base64Decoder(); + void append(const std::string &data); + + /* + * Function will return false when BIO_read fails + * (for example: when string was not in base64 format). + */ + bool finalize(); + std::string get() const; + void reset(); + ~Base64Decoder() + { + } + + private: + std::string m_input; + std::string m_output; + bool m_finalized; +}; +} // namespace ValidationCore + +#endif diff --git a/vcore/src/vcore/CRL.cpp b/vcore/src/vcore/CRL.cpp new file mode 100644 index 0000000..c21c884 --- /dev/null +++ b/vcore/src/vcore/CRL.cpp @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Piotr Marcinkiewicz(p.marcinkiew@samsung.com) + * @version 0.1 + * @file CRL.h + * @brief Routines for certificate validation over CRL + */ + +#include "CRL.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "Base64.h" +#include "Certificate.h" +#include "SoupMessageSendSync.h" +#include "CRLCacheInterface.h" + +namespace { +const char *CRL_LOOKUP_DIR_1 = "/usr/share/cert-svc/ca-certs/code-signing/wac"; +const char *CRL_LOOKUP_DIR_2 = "/opt/share/cert-svc/certs/code-signing/wac"; +} //anonymous namespace + +namespace ValidationCore { + +CRL::StringList CRL::getCrlUris(const CertificatePtr &argCert) +{ + StringList result = argCert->getCrlUris(); + + if (!result.empty()) { + return result; + } + LogInfo("No distribution points found. Getting from CA cert."); + X509_STORE_CTX *ctx = createContext(argCert); + X509_OBJECT obj; + + //Try to get distribution points from CA certificate + int retVal = X509_STORE_get_by_subject(ctx, X509_LU_X509, + X509_get_issuer_name(argCert-> + getX509()), + &obj); + X509_STORE_CTX_free(ctx); + if (0 >= retVal) { + LogError("No dedicated CA certificate available"); + return result; + } + CertificatePtr caCert(new Certificate(obj.data.x509)); + X509_OBJECT_free_contents(&obj); + return caCert->getCrlUris(); +} + +CRL::CRL(CRLCacheInterface *ptr) + : m_crlCache(ptr) +{ + Assert(m_crlCache != NULL); + + LogInfo("CRL storage initialization."); + m_store = X509_STORE_new(); + if (!m_store) { + LogError("Failed to create new store."); + ThrowMsg(CRLException::StorageError, + "Not possible to create new store."); + } + m_lookup = X509_STORE_add_lookup(m_store, X509_LOOKUP_hash_dir()); + if (!m_lookup) { + cleanup(); + LogError("Failed to add hash dir lookup"); + ThrowMsg(CRLException::StorageError, + "Not possible to add hash dir lookup."); + } + // Add hash dir pathname for CRL checks + bool retVal = X509_LOOKUP_add_dir(m_lookup, + CRL_LOOKUP_DIR_1, X509_FILETYPE_PEM) == 1; + retVal &= retVal && (X509_LOOKUP_add_dir(m_lookup, CRL_LOOKUP_DIR_1, + X509_FILETYPE_ASN1) == 1); + retVal &= retVal && (X509_LOOKUP_add_dir(m_lookup, CRL_LOOKUP_DIR_2, + X509_FILETYPE_PEM) == 1); + retVal &= retVal && (X509_LOOKUP_add_dir(m_lookup, CRL_LOOKUP_DIR_2, + X509_FILETYPE_ASN1) == 1); + if (!retVal) { + LogError("Failed to add lookup dir for PEM files."); + cleanup(); + ThrowMsg(CRLException::StorageError, + "Failed to add lookup dir for PEM files."); + } + LogInfo("CRL storage initialization complete."); +} + +CRL::~CRL() +{ + cleanup(); + delete m_crlCache; +} + +void CRL::cleanup() +{ + LogInfo("Free CRL storage"); + // STORE is responsible for LOOKUP release + // X509_LOOKUP_free(m_lookup); + X509_STORE_free(m_store); +} + +CRL::RevocationStatus CRL::checkCertificate(const CertificatePtr &argCert) +{ + RevocationStatus retStatus = {false, false}; + int retVal = 0; + StringList crlUris = getCrlUris(argCert); + FOREACH(it, crlUris) { + CRLDataPtr crl = getCRL(*it); + if (!crl) { + LogDebug("CRL not found for URI: " << *it); + continue; + } + X509_CRL *crlInternal = convertToInternal(crl); + + //Check date + if (X509_CRL_get_nextUpdate(crlInternal)) { + retVal = X509_cmp_current_time( + X509_CRL_get_nextUpdate(crlInternal)); + retStatus.isCRLValid = retVal > 0; + } else { + // If nextUpdate is not set assume it is actual. + retStatus.isCRLValid = true; + } + LogInfo("CRL valid: " << retStatus.isCRLValid); + X509_REVOKED rev; + rev.serialNumber = X509_get_serialNumber(argCert->getX509()); + // sk_X509_REVOKED_find returns index if serial number is found on list + retVal = sk_X509_REVOKED_find(crlInternal->crl->revoked, &rev); + X509_CRL_free(crlInternal); + retStatus.isRevoked = retVal != -1; + LogInfo("CRL revoked: " << retStatus.isRevoked); + + if (!retStatus.isRevoked && isOutOfDate(crl)) { + LogDebug("Certificate is not Revoked, but CRL is outOfDate."); + continue; + } + + return retStatus; + } + // If there is no CRL for any of URIs it means it's not possible to + // tell anything about revocation status but it's is not an error. + return retStatus; +} + +CRL::RevocationStatus CRL::checkCertificateChain(CertificateCollection + certChain) +{ + if (!certChain.sort()) { + LogError("Certificate list doesn't create chain."); + ThrowMsg(CRLException::InvalidParameter, + "Certificate list doesn't create chain."); + } + + RevocationStatus ret; + ret.isCRLValid = true; + ret.isRevoked = false; + const CertificateList &certList = certChain.getChain(); + FOREACH(it, certList) { + if (!(*it)->isRootCert()) { + LogInfo("Certificate common name: " << *((*it)->getCommonName())); + RevocationStatus certResult = checkCertificate(*it); + ret.isCRLValid &= certResult.isCRLValid; + ret.isRevoked |= certResult.isRevoked; + if (ret.isCRLValid && !ret.isRevoked) { + addToStore(*it); + } + if (ret.isRevoked) { + return ret; + } + } + } + return ret; +} + +VerificationStatus CRL::checkEndEntity(CertificateCollection &chain) +{ + if (!chain.sort() && !chain.empty()) { + LogInfo("Could not find End Entity certificate. " + "Collection does not form chain."); + return VERIFICATION_STATUS_ERROR; + } + CertificateList::const_iterator iter = chain.begin(); + RevocationStatus stat = checkCertificate(*iter); + if (stat.isRevoked) { + return VERIFICATION_STATUS_REVOKED; + } + if (stat.isCRLValid) { + return VERIFICATION_STATUS_GOOD; + } + return VERIFICATION_STATUS_ERROR; +} + +void CRL::addToStore(const CertificatePtr &argCert) +{ + X509_STORE_add_cert(m_store, argCert->getX509()); +} + +bool CRL::isOutOfDate(const CRLDataPtr &crl) const { + X509_CRL *crlInternal = convertToInternal(crl); + + bool result = false; + if (X509_CRL_get_nextUpdate(crlInternal)) { + if (0 > X509_cmp_current_time(X509_CRL_get_nextUpdate(crlInternal))) { + result = true; + } else { + result = false; + } + } else { + result = true; + } + X509_CRL_free(crlInternal); + return result; +} + +bool CRL::updateList(const CertificatePtr &argCert, + const UpdatePolicy updatePolicy) +{ + LogInfo("Update CRL for certificate"); + + // Retrieve distribution points + StringList crlUris = getCrlUris(argCert); + FOREACH(it, crlUris) { + // Try to get CRL from database + LogInfo("Getting CRL for URI: " << *it); + + bool downloaded = false; + + CRLDataPtr crl; + + // If updatePolicy == UPDATE_ON_DEMAND we dont care + // about data in cache. New crl must be downloaded. + if (updatePolicy == UPDATE_ON_EXPIRED) { + crl = getCRL(*it); + } + + if (!!crl && isOutOfDate(crl)) { + LogDebug("Crl out of date - downloading."); + crl = downloadCRL(*it); + downloaded = true; + } + + if (!crl) { + LogDebug("Crl not found in cache - downloading."); + crl = downloadCRL(*it); + downloaded = true; + } + + if (!crl) { + LogDebug("Failed to obtain CRL. URL: " << *it); + continue; + } + + if (!!crl && isOutOfDate(crl)) { + LogError("CRL out of date. Broken URL: " << *it); + } + + // Make X509 internal structure + X509_CRL *crlInternal = convertToInternal(crl); + + //Check if CRL is signed + if (!verifyCRL(crlInternal, argCert)) { + LogError("Failed to verify CRL. URI: " << crl->uri); + X509_CRL_free(crlInternal); + return false; + } + X509_CRL_free(crlInternal); + + if (downloaded) { + updateCRL(crl); + } + return true; + } + + return false; +} + +void CRL::addToStore(const CertificateCollection &collection) +{ + FOREACH(it, collection){ + addToStore(*it); + } +} + +bool CRL::updateList(const CertificateCollection &collection, + UpdatePolicy updatePolicy) +{ + bool failed = false; + + FOREACH(it, collection){ + failed |= !updateList(*it, updatePolicy); + } + + return !failed; +} + +bool CRL::verifyCRL(X509_CRL *crl, + const CertificatePtr &cert) +{ + X509_OBJECT obj; + X509_STORE_CTX *ctx = createContext(cert); + + /* get issuer certificate */ + int retVal = X509_STORE_get_by_subject(ctx, X509_LU_X509, + X509_CRL_get_issuer(crl), &obj); + X509_STORE_CTX_free(ctx); + if (0 >= retVal) { + LogError("Unknown CRL issuer certificate!"); + return false; + } + + /* extract public key and verify signature */ + EVP_PKEY *pkey = X509_get_pubkey(obj.data.x509); + X509_OBJECT_free_contents(&obj); + if (!pkey) { + LogError("Failed to get issuer's public key."); + return false; + } + retVal = X509_CRL_verify(crl, pkey); + EVP_PKEY_free(pkey); + if (0 > retVal) { + LogError("Failed to verify CRL."); + return false; + } else if (0 == retVal) { + LogError("CRL is invalid"); + return false; + } + LogInfo("CRL is valid."); + return true; +} + +bool CRL::isPEMFormat(const CRLDataPtr &crl) const +{ + const char *pattern = "-----BEGIN X509 CRL-----"; + std::string content(crl->buffer, crl->length); + if (content.find(pattern) != std::string::npos) { + LogInfo("CRL is in PEM format."); + return true; + } + LogInfo("CRL is in DER format."); + return false; +} + +X509_CRL *CRL::convertToInternal(const CRLDataPtr &crl) const +{ + //At this point it's not clear does crl have DER or PEM format + X509_CRL *ret = NULL; + if (isPEMFormat(crl)) { + BIO *bmem = BIO_new_mem_buf(crl->buffer, crl->length); + if (!bmem) { + LogError("Failed to allocate memory in BIO"); + ThrowMsg(CRLException::InternalError, + "Failed to allocate memory in BIO"); + } + ret = PEM_read_bio_X509_CRL(bmem, NULL, NULL, NULL); + BIO_free_all(bmem); + } else { + //If it's not PEM it must be DER format + std::string content(crl->buffer, crl->length); + const unsigned char *buffer = + reinterpret_cast(crl->buffer); + ret = d2i_X509_CRL(NULL, &buffer, crl->length); + } + if (!ret) { + LogError("Failed to convert to internal structure"); + ThrowMsg(CRLException::InternalError, + "Failed to convert to internal structure"); + } + return ret; +} + +X509_STORE_CTX *CRL::createContext(const CertificatePtr &argCert) +{ + X509_STORE_CTX *ctx; + ctx = X509_STORE_CTX_new(); + if (!ctx) { + ThrowMsg(CRLException::StorageError, "Failed to create new context."); + } + X509_STORE_CTX_init(ctx, m_store, argCert->getX509(), NULL); + return ctx; +} + +CRL::CRLDataPtr CRL::downloadCRL(const std::string &uri) +{ + using namespace SoupWrapper; + + char *cport = 0, *chost = 0,*cpath = 0; + int use_ssl = 0; + + if (!OCSP_parse_url(const_cast(uri.c_str()), + &chost, + &cport, + &cpath, + &use_ssl)) + { + LogWarning("Error in OCSP_parse_url"); + return CRLDataPtr(); + } + + std::string host = chost; + if (cport) { + host += ":"; + host += cport; + } + + free(cport); + free(chost); + free(cpath); + + SoupMessageSendSync message; + message.setHost(uri); + message.setHeader("Host", host); + + if (SoupMessageSendSync::REQUEST_STATUS_OK != message.sendSync()) { + LogWarning("Error in sending network request."); + return CRLDataPtr(); + } + + SoupMessageSendBase::MessageBuffer mBuffer = message.getResponse(); + return CRLDataPtr(new CRLData(mBuffer,uri)); +} + +CRL::CRLDataPtr CRL::getCRL(const std::string &uri) const +{ + CRLCachedData cachedCrl; + cachedCrl.distribution_point = uri; + if (!(m_crlCache->getCRLResponse(&cachedCrl))) { + LogInfo("CRL not present in database. URI: " << uri); + return CRLDataPtr(); + } + + std::string body = cachedCrl.crl_body; + + LogInfo("CRL found in database."); + //TODO: remove when ORM::blob available + //Encode buffer to base64 format to store in database + + Base64Decoder decoder; + decoder.append(body); + if (!decoder.finalize()) { + LogError("Failed to decode base64 format."); + ThrowMsg(CRLException::StorageError, "Failed to decode base64 format."); + } + std::string crlBody = decoder.get(); + + DPL::ScopedArray bodyBuffer(new char[crlBody.length()]); + crlBody.copy(bodyBuffer.Get(), crlBody.length()); + return CRLDataPtr(new CRLData(bodyBuffer.Release(), crlBody.length(), + uri)); +} + +void CRL::updateCRL(const CRLDataPtr &crl) +{ + //TODO: remove when ORM::blob available + //Encode buffer to base64 format to store in database + Base64Encoder encoder; + if (!crl || !crl->buffer) { + ThrowMsg(CRLException::InternalError, "CRL buffer is empty"); + } + encoder.append(std::string(crl->buffer, crl->length)); + encoder.finalize(); + std::string b64CRLBody = encoder.get(); + + time_t nextUpdateTime = 0; + X509_CRL *crlInternal = convertToInternal(crl); + + if (X509_CRL_get_nextUpdate(crlInternal)) { + asn1TimeToTimeT(X509_CRL_get_nextUpdate(crlInternal), + &nextUpdateTime); + } + + X509_CRL_free(crlInternal); + //Update/insert crl body + CRLCachedData data; + data.distribution_point = crl->uri; + data.crl_body = b64CRLBody; + data.next_update_time = nextUpdateTime; + + m_crlCache->setCRLResponse(&data); +} +} // ValidationCore diff --git a/vcore/src/vcore/CRL.h b/vcore/src/vcore/CRL.h new file mode 100644 index 0000000..c1e180a --- /dev/null +++ b/vcore/src/vcore/CRL.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Piotr Marcinkiewicz(p.marcinkiew@samsung.com) + * @version 0.4 + * @file CRL.h + * @brief Routines for certificate validation over CRL + */ + +#ifndef WRT_ENGINE_SRC_VALIDATION_CORE_ENGINE_CRL_H_ +#define WRT_ENGINE_SRC_VALIDATION_CORE_ENGINE_CRL_H_ + +#include +#include +#include +#include + +#include "Certificate.h" +#include "CertificateCollection.h" +#include "SoupMessageSendBase.h" +#include "VerificationStatus.h" +#include "CRLCacheInterface.h" + +namespace ValidationCore { +namespace CRLException { +DECLARE_EXCEPTION_TYPE(DPL::Exception, CRLException) +DECLARE_EXCEPTION_TYPE(CRLException, StorageError) +DECLARE_EXCEPTION_TYPE(CRLException, DownloadFailed) +DECLARE_EXCEPTION_TYPE(CRLException, InternalError) +DECLARE_EXCEPTION_TYPE(CRLException, InvalidParameter) +} + +class CRL : DPL::Noncopyable +{ + protected: + X509_STORE *m_store; + X509_LOOKUP *m_lookup; + CRLCacheInterface *m_crlCache; + + class CRLData : DPL::Noncopyable + { + public: + //TODO: change to SharedArray when available + char *buffer; + size_t length; + std::string uri; + + CRLData(char* _buffer, + size_t _length, + const std::string &_uri) : + buffer(_buffer), + length(_length), + uri(_uri) + { + } + + CRLData(const SoupWrapper::SoupMessageSendBase::MessageBuffer &mBuff, + const std::string &mUri) + : uri(mUri) + { + buffer = new char[mBuff.size()]; + length = mBuff.size(); + memcpy(buffer, &mBuff[0], mBuff.size()); + } + + ~CRLData() + { + LogInfo("Delete buffer"); + delete[] buffer; + } + }; + typedef DPL::SharedPtr CRLDataPtr; + typedef std::list StringList; + + CRLDataPtr getCRL(const std::string &uri) const; + CRLDataPtr downloadCRL(const std::string &uri); + X509_STORE_CTX *createContext(const CertificatePtr &argCert); + void updateCRL(const CRLDataPtr &crl); + X509_CRL *convertToInternal(const CRLDataPtr &crl) const; + StringList getCrlUris(const CertificatePtr &argCert); + bool isPEMFormat(const CRLDataPtr &crl) const; + bool verifyCRL(X509_CRL *crl, + const CertificatePtr &cert); + void cleanup(); + bool isOutOfDate(const CRLDataPtr &crl) const; + + friend class CachedCRL; + public: + enum UpdatePolicy + { + UPDATE_ON_EXPIRED, /**< Download and update CRL only when next update + date has expired */ + UPDATE_ON_DEMAND /**< Download and update CRL regardless next update + date */ + }; + + struct RevocationStatus + { + bool isCRLValid; /**< True when CRL was valid during + certificate validation */ + bool isRevoked; /**< True when certificate is revoked */ + }; + + CRL(CRLCacheInterface *ptr); + ~CRL(); + + /** + * @brief Checks if given certificate is revoked. + * + * @details This function doesn't update CRL list. If related CRL + * is out of date the #isCRLValid return parameter is set to false. + * + * @param[in] argCert The certificate to check against revocation. + * @return RevocationStatus.isRevoked True when certificate is revoked, + * false otherwise. + * RevocationStatus.isCRLValid True if related CRL has not expired, + * false otherwise. + */ + RevocationStatus checkCertificate(const CertificatePtr &argCert); + + /** + * @brief Checks if any certificate from certificate chain is revoked. + * + * @details This function doesn't update CRL lists. If any of related + * CRL is out of date the #isCRLValid parameter is set to true. + * This function adds valid certificates from the chain to internal storage + * map so they'll be available in further check operations for current + * CRL object. + * + * @param[in] argCert The certificate chain to check against revocation. + * @return RevocationStatus.isRevoked True when any from certificate chain + * is revoked, false otherwise. + * RevocationStatus.isCRLValid True if all of related CRLs has + * not expired, false otherwise. + */ + RevocationStatus checkCertificateChain(CertificateCollection certChain); + + VerificationStatus checkEndEntity(CertificateCollection &chain); + + /** + * @brief Updates CRL related with given certificate. + * + * @details This function updates CRL list related with given certificate. + * If CRL related with given certificate is not stored in database + * then this function will download CRL and store it in database. + * + * @param[in] argCert The certificate for which the CRL will be updated + * @param[in] updatePolicy Determine when CRL will be downloaded and updated + * @return True when CRL for given certificate was updated successfully, + * false otherwise. + */ + bool updateList(const CertificatePtr &argCert, + const UpdatePolicy updatePolicy); + + /** + * @brief Updates CRL related with given certificates. + * + * @details This function updates CRL lists related with given certificates. + * If CRL related with given certificate is not stored in database + * then this function will download CRL and store it in database. + * + * @param[in] collection The certificate collection for which the CRL will + * be updated + * @param[in] updatePolicy Determine when CRL will be downloaded and updated + * @return True when CRL for given certificate was updated successfully, + * false otherwise. + */ + bool updateList(const CertificateCollection &collection, + const UpdatePolicy updatePolisy); + + /** + * @brief Add certificates to trusted certificates store. + * + * @param[in] collection The certificate collection which will be + * added to known certificate store. + */ + void addToStore(const CertificateCollection &collection); + + /** + * @brief Add one certificate to trusted certificates store. + * + * @param[in] collection The certificate collection which will be + * added to known certificate store. + */ + void addToStore(const CertificatePtr &argCert); +}; +} // ValidationCore + +#endif //ifndef WRT_ENGINE_SRC_VALIDATION_CORE_ENGINE_CRL_H_ diff --git a/vcore/src/vcore/CRLCacheDAO.cpp b/vcore/src/vcore/CRLCacheDAO.cpp new file mode 100644 index 0000000..ad7fc86 --- /dev/null +++ b/vcore/src/vcore/CRLCacheDAO.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 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. + */ +/* + * @author Bartlomiej Grzelewski(b.grzelewski@samsung.com) + * @version 0.1 + * @file CRLCacheDAO.cpp + * @brief CRLCacheInterface implementation. + */ + +#include +#include + +namespace ValidationCore { + +bool CRLCacheDAO::getCRLResponse(CRLCachedData *ptr){ + return CertificateCacheDAO::getCRLResponse(ptr); +} + +void CRLCacheDAO::setCRLResponse(CRLCachedData *ptr){ + CertificateCacheDAO::setCRLResponse(ptr); +} + +} // namespace ValidationCore diff --git a/vcore/src/vcore/CRLCacheDAO.h b/vcore/src/vcore/CRLCacheDAO.h new file mode 100644 index 0000000..2dca09b --- /dev/null +++ b/vcore/src/vcore/CRLCacheDAO.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011 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. + */ +/* + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 0.1 + * @file CRLCacheDAO.h + * @brief CRLCacheInterface implementation. + */ +#ifndef _CRLCACHEDAO_H_ +#define _CRLCACHEDAO_H_ + +#include + +namespace ValidationCore { + +class CRLCacheDAO : public CRLCacheInterface { +public: + virtual bool getCRLResponse(CRLCachedData *ptr); + virtual void setCRLResponse(CRLCachedData *ptr); +}; + +} // namespace ValidationCore + +#endif diff --git a/vcore/src/vcore/CRLCacheInterface.h b/vcore/src/vcore/CRLCacheInterface.h new file mode 100644 index 0000000..1d17078 --- /dev/null +++ b/vcore/src/vcore/CRLCacheInterface.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Bartlomiej Grzelewski(b.grzelewski@samsung.com) + * @version 0.1 + * @file CRLCacheInterface.h + * @brief CRLCacheInterface definition. + */ +#ifndef _CRLCACHEINTERFACE_H_ +#define _CRLCACHEINTERFACE_H_ + +#include + +namespace ValidationCore { + +struct CRLCachedData +{ + std::string distribution_point; + std::string crl_body; + time_t next_update_time; +}; + +class CRLCacheInterface { +public: + virtual bool getCRLResponse(CRLCachedData *ptr) = 0; + virtual void setCRLResponse(CRLCachedData *ptr) = 0; +}; + +} // namespace ValidationCore + +#endif diff --git a/vcore/src/vcore/CachedCRL.cpp b/vcore/src/vcore/CachedCRL.cpp new file mode 100644 index 0000000..74b7f3f --- /dev/null +++ b/vcore/src/vcore/CachedCRL.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2011 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 CachedCRL.cpp + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 0.1 + * @brief Cached CRL class implementation + */ + +#include +#include + +#include +#include +#include + +#include "CRL.h" +#include "CachedCRL.h" +#include "Certificate.h" +#include "CertificateCacheDAO.h" +#include "CRLCacheDAO.h" + +namespace ValidationCore { + +const time_t CachedCRL::CRL_minTimeValid = 3600; // one hour in seconds + +const time_t CachedCRL::CRL_maxTimeValid = 3600 * 24 * 7; // one week in seconds + +const time_t CachedCRL::CRL_refreshBefore = 3600; // one hour in seconds + +VerificationStatus CachedCRL::check(const CertificateCollection &certs) +{ + CRL crl(new CRLCacheDAO); + bool allValid = true; + // we dont check CRL validity since + // we may use crl for longer time + // in smart cache than in regular CRL class (time clamping) + crl.addToStore(certs); + FOREACH(cert, certs){ + CRL::StringList crlUris = crl.getCrlUris(*cert); + FOREACH(uri, crlUris) { + allValid = allValid && updateCRLForUri(*uri,false); + } + } + if (!allValid) { + // problems with CRL validity + LogDebug("Some CRLs not valid"); + } + CRL::RevocationStatus stat; + Try { + stat = crl.checkCertificateChain(certs); + } Catch(CRLException::InvalidParameter) { + // List does not form a chain + return VERIFICATION_STATUS_ERROR; + } + if (stat.isRevoked) { + LogDebug("Status REVOKED"); + return VERIFICATION_STATUS_REVOKED; + } + LogDebug("Status GOOD"); + return VERIFICATION_STATUS_GOOD; +} + +VerificationStatus CachedCRL::checkEndEntity(CertificateCollection &certs) +{ + if (certs.empty()) { + LogError("Collection empty. This should never happen."); + LogDebug("Status ERROR"); + return VERIFICATION_STATUS_ERROR; + } + if (!certs.sort()) { + LogError("Could not find End Entity certificate. " + "Collection does not form chain."); + LogDebug("Status ERROR"); + return VERIFICATION_STATUS_ERROR; + } + CRL crl(new CRLCacheDAO); + bool allValid = true; + // we dont check CRL validity since + // we may use crl for longer time + // in smart cache than in regular CRL class (time clamping) + crl.addToStore(certs); + CertificateList::const_iterator icert = certs.begin(); + if (icert != certs.end()) { + CRL::StringList crlUris = crl.getCrlUris(*icert); + FOREACH(uri, crlUris) { + allValid = allValid && updateCRLForUri(*uri,false); + } + } + if (!allValid) { + // problems with CRL validity + LogDebug("Some CRLs not valid"); + } + CertificateList::const_iterator iter = certs.begin(); + CRL::RevocationStatus stat = crl.checkCertificate(*iter); + if (stat.isRevoked) { + LogDebug("Status REVOKED"); + return VERIFICATION_STATUS_REVOKED; + } + LogDebug("Status GOOD"); + return VERIFICATION_STATUS_GOOD; +} + +void CachedCRL::updateCache() +{ + CRLCachedDataList list; + CertificateCacheDAO::getCRLResponseList(&list); + FOREACH(db_crl, list) { + updateCRLForUri(db_crl->distribution_point, true); + } +} + +bool CachedCRL::updateCRLForUri(const std::string & uri, bool useExpiredShift) +{ + CRLCachedData cachedCRL; + cachedCRL.distribution_point = uri; + time_t now; + time(&now); + if (useExpiredShift) { + now += CRL_refreshBefore; + } + if (CertificateCacheDAO::getCRLResponse(&cachedCRL)) { + if (now < cachedCRL.next_update_time) { + LogDebug("Cached CRL still valid for: " << uri); + return true; + } + } + // need to download new CRL + CRL crl(new CRLCacheDAO); + CRL::CRLDataPtr list = crl.downloadCRL(uri); + if (!list) { + LogWarning("Could not retreive CRL from " << uri); + return false; + } + crl.updateCRL(list); + CertificateCacheDAO::getCRLResponse(&cachedCRL); // save it the way CRL does + cachedCRL.next_update_time = + getNextUpdateTime(now,cachedCRL.next_update_time); + CertificateCacheDAO::setCRLResponse(cachedCRL.distribution_point, + cachedCRL.crl_body, + cachedCRL.next_update_time); + return true; +} + +time_t CachedCRL::getNextUpdateTime(time_t now, time_t response_validity) +{ + time_t min = now + CRL_minTimeValid; + time_t max = now + CRL_maxTimeValid; + if (response_validity < min) { + return min; + } + if (response_validity > max) { + return max; + } + return response_validity; +} + +} // namespace ValidationCore diff --git a/vcore/src/vcore/CachedCRL.h b/vcore/src/vcore/CachedCRL.h new file mode 100644 index 0000000..65e6509 --- /dev/null +++ b/vcore/src/vcore/CachedCRL.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011 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 CachedCRL.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 0.1 + * @brief Header file for smart cached CRL class + */ + +#ifndef _SRC_VALIDATION_CORE_CACHED_CRL_ +#define _SRC_VALIDATION_CORE_CACHED_CRL_ + +#include "CRL.h" +#include "IAbstractResponseCache.h" + +namespace ValidationCore { + +class CachedCRL : public IAbstractResponseCache { + public: + // cache can't be refreshed more frequently than CRL_minTimeValid + static const time_t CRL_minTimeValid; + + // to be even more secure, cache will be refreshed for certificate at least + // after CRL_maxTimeValid from last response + static const time_t CRL_maxTimeValid; + + // upon cache refresh, responses that will be invalid in CRL_refreshBefore + // seconds will be refreshed + static const time_t CRL_refreshBefore; + + VerificationStatus check(const CertificateCollection &certs); + VerificationStatus checkEndEntity(CertificateCollection &certs); + void updateCache(); + + CachedCRL() + { + } + virtual ~CachedCRL() + { + } + + private: + + // updates CRL cache for distributor URI + // useExpiredShift ==true should be used in cron/global cache update + // since it updates all CRLs that will be out of date in next + // CRL_refreshBefore seconds + bool updateCRLForUri(const std::string & uri, + bool useExpiredShift); + time_t getNextUpdateTime(time_t now, time_t response_validity); +}; + +} // namespace ValidationCore + +#endif /* _SRC_VALIDATION_CORE_CACHED_CRL_ */ diff --git a/vcore/src/vcore/CachedOCSP.cpp b/vcore/src/vcore/CachedOCSP.cpp new file mode 100644 index 0000000..dc4e436 --- /dev/null +++ b/vcore/src/vcore/CachedOCSP.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2011 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 CachedOCSP.cpp + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 0.1 + * @brief Cached OCSP class implementation + */ + +#include +#include + +#include +#include +#include + +#include "OCSP.h" +#include "CachedOCSP.h" +#include "Certificate.h" +#include "CertificateCacheDAO.h" + +namespace ValidationCore { + +const time_t CachedOCSP::OCSP_minTimeValid = 3600; // one hour in seconds + +const time_t CachedOCSP::OCSP_maxTimeValid = + 3600 * 24 * 7; // one week in seconds + +const time_t CachedOCSP::OCSP_refreshBefore = 3600; // one hour in seconds + +VerificationStatus CachedOCSP::check(const CertificateCollection &certs) +{ + OCSPCachedStatus db_status; + time_t now; + time(&now); + + db_status.cert_chain = certs.toBase64String(); + db_status.end_entity_check = false; + + if (CertificateCacheDAO::getOCSPStatus(&db_status)) { + LogDebug("Found cache entry for OCSP"); + if (now < db_status.next_update_time) { + LogDebug("Cache response valid"); + return db_status.ocsp_status; + } + } + + // here we need to get OCSP result and add/update cache + OCSP ocsp; + CertificateList list = certs.getChain(); + ocsp.setTrustedStore(list); + + VerificationStatusSet statusSet = ocsp.validateCertificateList(list); + db_status.ocsp_status = statusSet.convertToStatus(); + db_status.next_update_time = ocsp.getResponseValidity(); + CertificateCacheDAO::setOCSPStatus(db_status.cert_chain, + db_status.ocsp_status, + db_status.end_entity_check, + getNextUpdateTime( + now, + db_status.next_update_time)); + return db_status.ocsp_status; +} + +VerificationStatus CachedOCSP::checkEndEntity(CertificateCollection &certs) +{ + OCSPCachedStatus db_status; + time_t now; + time(&now); + + db_status.cert_chain = certs.toBase64String(); + db_status.end_entity_check = true; + + if (CertificateCacheDAO::getOCSPStatus(&db_status)) { + LogDebug("Found cache entry for OCSP"); + if (now < db_status.next_update_time) { + LogDebug("Cache response valid"); + return db_status.ocsp_status; + } + } + + // here we need to send request via OCSP and add/update cache + CertificateList clst; + getCertsForEndEntity(certs, &clst); + + OCSP ocsp; + ocsp.setTrustedStore(certs.getCertificateList()); + + const char *defResponderURI = getenv(OCSP::DEFAULT_RESPONDER_URI_ENV); + + if (defResponderURI) { + ocsp.setUseDefaultResponder(true); + ocsp.setDefaultResponder(defResponderURI); + } + + VerificationStatusSet statusSet = ocsp.validateCertificateList(clst); + db_status.ocsp_status = statusSet.convertToStatus(); + db_status.next_update_time = ocsp.getResponseValidity(); + + CertificateCacheDAO::setOCSPStatus(db_status.cert_chain, + db_status.ocsp_status, + db_status.end_entity_check, + getNextUpdateTime( + now, + db_status.next_update_time)); + + return db_status.ocsp_status; +} + +void CachedOCSP::updateCache() +{ + time_t now; + time(&now); + now += OCSP_refreshBefore; + OCSPCachedStatusList list; + CertificateCacheDAO::getOCSPStatusList(&list); + FOREACH(db_status, list) { + if (now >= db_status->next_update_time) { + // this response needs to be refreshed + CertificateCollection col; + col.load(db_status->cert_chain); + if (!col.sort()) { + LogError("Certificate collection does not create chain."); + continue; + } + + OCSP ocsp; + CertificateList chain = col.getChain(); + ocsp.setTrustedStore(chain); + + VerificationStatusSet statusSet; + + if (db_status->end_entity_check) { + CertificateList clst; + getCertsForEndEntity(col, &clst); + statusSet = ocsp.validateCertificateList(clst); + } else { + statusSet = ocsp.validateCertificateList(chain); + } + + db_status->ocsp_status = statusSet.convertToStatus(); + db_status->next_update_time = ocsp.getResponseValidity(); + + CertificateCacheDAO::setOCSPStatus(db_status->cert_chain, + db_status->ocsp_status, + db_status->end_entity_check, + db_status->next_update_time); + } + } +} + +void CachedOCSP::getCertsForEndEntity( + const CertificateCollection &certs, CertificateList* clst) +{ + if (NULL == clst) { + LogError("NULL pointer"); + return; + } + + if (certs.isChain() && certs.size() >= 2) { + CertificateList::const_iterator icert = certs.begin(); + clst->push_back(*icert); + ++icert; + clst->push_back(*icert); + } +} + +time_t CachedOCSP::getNextUpdateTime(time_t now, time_t response_validity) +{ + long min = now + OCSP_minTimeValid; + long max = now + OCSP_maxTimeValid; + if (response_validity < min) { + return min; + } + if (response_validity > max) { + return max; + } + return response_validity; +} + +} // namespace ValidationCore diff --git a/vcore/src/vcore/CachedOCSP.h b/vcore/src/vcore/CachedOCSP.h new file mode 100644 index 0000000..517e49f --- /dev/null +++ b/vcore/src/vcore/CachedOCSP.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011 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 CachedOCSP.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 0.1 + * @brief Header file for smart cached OCSP class + */ + +#ifndef _SRC_VALIDATION_CORE_CACHED_OCSP_ +#define _SRC_VALIDATION_CORE_CACHED_OCSP_ + +#include "OCSP.h" +#include "IAbstractResponseCache.h" + +namespace ValidationCore { + +class CachedOCSP : public IAbstractResponseCache { + public: + // cache can't be refreshed more frequently than OCSP_minTimeValid + static const time_t OCSP_minTimeValid; + + // to be even more secure, cache will be refreshed for certificate at least + // after OCSP_minTimeValid from last response + static const time_t OCSP_maxTimeValid; + + // upon cache refresh, responses that will be invalid in OCSP_refreshBefore + // seconds will be refreshed + static const time_t OCSP_refreshBefore; + + VerificationStatus check(const CertificateCollection &certs); + VerificationStatus checkEndEntity(CertificateCollection &certs); + void updateCache(); + + CachedOCSP() + { + } + virtual ~CachedOCSP() + { + } + + private: + + void getCertsForEndEntity(const CertificateCollection &certs, + CertificateList* clst); + time_t getNextUpdateTime(time_t now, time_t response_validity); +}; + +} // namespace ValidationCore + +#endif /* _SRC_VALIDATION_CORE_CACHED_OCSP_ */ diff --git a/vcore/src/vcore/CertStoreType.h b/vcore/src/vcore/CertStoreType.h new file mode 100644 index 0000000..7cf6232 --- /dev/null +++ b/vcore/src/vcore/CertStoreType.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011 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 + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ +#ifndef _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_CERTSTORETYPE_H_ +#define _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_CERTSTORETYPE_H_ + +namespace ValidationCore { +namespace CertStoreId { +typedef unsigned int Type; + +// RootCA certificates for developer mode. +const Type DEVELOPER = 1; +// RootCA certificates for author signatures. +const Type WAC_PUBLISHER = 1 << 1; +// RootCA certificates for wac-signed widgets. +const Type WAC_ROOT = 1 << 2; +// RootCA certificates for wac-members ie. operators, manufacturers. +const Type WAC_MEMBER = 1 << 3; + +class Set +{ + public: + Set() : + m_certificateStorage(0) + { + } + + void add(Type second) + { + m_certificateStorage |= second; + } + + bool contains(Type second) const + { + return static_cast(m_certificateStorage & second); + } + + bool isEmpty() const + { + return m_certificateStorage == 0; + } + + private: + Type m_certificateStorage; +}; +} // namespace CertStoreId +} // namespace ValidationCore + +#endif // _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_CERTSTORETYPE_H_ diff --git a/vcore/src/vcore/Certificate.cpp b/vcore/src/vcore/Certificate.cpp new file mode 100644 index 0000000..23679f2 --- /dev/null +++ b/vcore/src/vcore/Certificate.cpp @@ -0,0 +1,645 @@ +/* + * Copyright (c) 2011 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 Certificate.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ +#include "Certificate.h" + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +namespace ValidationCore { + +int asn1TimeToTimeT(ASN1_TIME *t, + time_t *res) +{ + struct tm tm; + int offset; + + (*res) = 0; + if (!ASN1_TIME_check(t)) { + return -1; + } + + memset(&tm, 0, sizeof(tm)); + +#define g2(p) (((p)[0] - '0') * 10 + (p)[1] - '0') + if (t->type == V_ASN1_UTCTIME) { + Assert(t->length > 12); + + /* this code is copied from OpenSSL asn1/a_utctm.c file */ + tm.tm_year = g2(t->data); + if (tm.tm_year < 50) { + tm.tm_year += 100; + } + tm.tm_mon = g2(t->data + 2) - 1; + tm.tm_mday = g2(t->data + 4); + tm.tm_hour = g2(t->data + 6); + tm.tm_min = g2(t->data + 8); + tm.tm_sec = g2(t->data + 10); + if (t->data[12] == 'Z') { + offset = 0; + } else { + Assert(t->length > 16); + + offset = g2(t->data + 13) * 60 + g2(t->data + 15); + if (t->data[12] == '-') { + offset = -offset; + } + } + tm.tm_isdst = -1; + } else { + Assert(t->length > 14); + + tm.tm_year = g2(t->data) * 100 + g2(t->data + 2); + tm.tm_mon = g2(t->data + 4) - 1; + tm.tm_mday = g2(t->data + 6); + tm.tm_hour = g2(t->data + 8); + tm.tm_min = g2(t->data + 10); + tm.tm_sec = g2(t->data + 12); + if (t->data[14] == 'Z') { + offset = 0; + } else { + Assert(t->length > 18); + + offset = g2(t->data + 15) * 60 + g2(t->data + 17); + if (t->data[14] == '-') { + offset = -offset; + } + } + tm.tm_isdst = -1; + } +#undef g2 + (*res) = timegm(&tm) - offset * 60; + return 0; +} + +int asn1GeneralizedTimeToTimeT(ASN1_GENERALIZEDTIME *tm, + time_t *res) +{ + /* + * This code is based on following assumption: + * from openssl/a_gentm.c: + * GENERALIZEDTIME is similar to UTCTIME except the year is + * represented as YYYY. This stuff treats everything as a two digit + * field so make first two fields 00 to 99 + */ + const int DATE_BUFFER_LENGTH = 15; // YYYYMMDDHHMMSSZ + + if (NULL == res || NULL == tm) { + LogError("NULL pointer"); + return -1; + } + + if (DATE_BUFFER_LENGTH != tm->length || NULL == tm->data) { + LogError("Invalid ASN1_GENERALIZEDTIME"); + return -1; + } + + struct tm time_s; + if (sscanf ((char*)tm->data, + "%4d%2d%2d%2d%2d%2d", + &time_s.tm_year, + &time_s.tm_mon, + &time_s.tm_mday, + &time_s.tm_hour, + &time_s.tm_min, + &time_s.tm_sec) < 6) + { + LogError("Could not extract time data from ASN1_GENERALIZEDTIME"); + return -1; + } + + time_s.tm_year -= 1900; + time_s.tm_mon -= 1; + time_s.tm_isdst = 0; // UTC + time_s.tm_gmtoff = 0; // UTC + time_s.tm_zone = NULL; // UTC + + *res = mktime(&time_s); + + return 0; +} + +Certificate::Certificate(X509 *cert) +{ + Assert(cert); + m_x509 = X509_dup(cert); + if (!m_x509) { + LogWarning("Internal Openssl error in d2i_X509 function."); + ThrowMsg(Exception::OpensslInternalError, + "Internal Openssl error in d2i_X509 function."); + } +} + +Certificate::Certificate(cert_svc_mem_buff &buffer) +{ + Assert(buffer.data); + const unsigned char *ptr = buffer.data; + m_x509 = d2i_X509(NULL, &ptr, buffer.size); + if (!m_x509) { + LogWarning("Internal Openssl error in d2i_X509 function."); + ThrowMsg(Exception::OpensslInternalError, + "Internal Openssl error in d2i_X509 function."); + } +} + +Certificate::Certificate(const std::string &der, + Certificate::FormType form) +{ + Assert(der.size()); + + int size; + const unsigned char *ptr; + std::string tmp; + + if (FORM_BASE64 == form) { + Base64Decoder base64; + base64.reset(); + base64.append(der); + base64.finalize(); + tmp = base64.get(); + ptr = reinterpret_cast(tmp.c_str()); + size = static_cast(tmp.size()); + } else { + ptr = reinterpret_cast(der.c_str()); + size = static_cast(der.size()); + } + + m_x509 = d2i_X509(NULL, &ptr, size); + if (!m_x509) { + LogError("Internal Openssl error in d2i_X509 function."); + ThrowMsg(Exception::OpensslInternalError, + "Internal Openssl error in d2i_X509 function."); + } +} + +Certificate::~Certificate() +{ + X509_free(m_x509); +} + +X509* Certificate::getX509(void) const +{ + return m_x509; +} + +std::string Certificate::getDER(void) const +{ + unsigned char *rawDer = NULL; + int size = i2d_X509(m_x509, &rawDer); + if (!rawDer || size <= 0) { + LogError("i2d_X509 failed"); + ThrowMsg(Exception::OpensslInternalError, + "i2d_X509 failed"); + } + + std::string output(reinterpret_cast(rawDer), size); + OPENSSL_free(rawDer); + return output; +} + +std::string Certificate::getBase64(void) const +{ + Base64Encoder base64; + base64.reset(); + base64.append(getDER()); + base64.finalize(); + return base64.get(); +} + +bool Certificate::isSignedBy(const CertificatePtr &parent) const +{ + if (!parent) { + LogDebug("Invalid certificate parameter."); + return false; + } + return 0 == X509_NAME_cmp(X509_get_subject_name(parent->m_x509), + X509_get_issuer_name(m_x509)); +} + +Certificate::Fingerprint Certificate::getFingerprint( + Certificate::FingerprintType type) const +{ + size_t fingerprintlength = EVP_MAX_MD_SIZE; + unsigned char fingerprint[EVP_MAX_MD_SIZE]; + Fingerprint raw; + + if (type == FINGERPRINT_MD5) { + if (!X509_digest(m_x509, EVP_md5(), fingerprint, &fingerprintlength)) { + LogError("MD5 digest counting failed!"); + ThrowMsg(Exception::OpensslInternalError, + "MD5 digest counting failed!"); + } + } + + if (type == FINGERPRINT_SHA1) { + if (!X509_digest(m_x509, EVP_sha1(), fingerprint, + &fingerprintlength)) + { + LogError("SHA1 digest counting failed"); + ThrowMsg(Exception::OpensslInternalError, + "SHA1 digest counting failed!"); + } + } + + raw.resize(fingerprintlength); // improve performance + std::copy(fingerprint, fingerprint + fingerprintlength, raw.begin()); + + return raw; +} + +X509_NAME *Certificate::getX509Name(FieldType type) const +{ + X509_NAME *name = NULL; + + switch (type) { + case FIELD_ISSUER: + name = X509_get_issuer_name(m_x509); + break; + case FIELD_SUBJECT: + name = X509_get_subject_name(m_x509); + break; + default: + Assert("Invalid field type."); + } + + if (!name) { + LogError("Error during x509 name extraction."); + ThrowMsg(Exception::OpensslInternalError, + "Error during x509 name extraction."); + } + + return name; +} + +DPL::String Certificate::getOneLine(FieldType type) const +{ + X509_NAME *name = getX509Name(type); + static const int MAXB = 1024; + char buffer[MAXB]; + X509_NAME_oneline(name, buffer, MAXB); + return DPL::FromUTF8String(buffer); +} + +DPL::OptionalString Certificate::getField(FieldType type, + int fieldNid) const +{ + X509_NAME *subjectName = getX509Name(type); + X509_NAME_ENTRY *subjectEntry = NULL; + DPL::Optional < DPL::String > output; + int entryCount = X509_NAME_entry_count(subjectName); + + for (int i = 0; i < entryCount; ++i) { + subjectEntry = X509_NAME_get_entry(subjectName, + i); + + if (!subjectEntry) { + continue; + } + + int nid = OBJ_obj2nid( + static_cast( + X509_NAME_ENTRY_get_object(subjectEntry))); + + if (nid != fieldNid) { + continue; + } + + ASN1_STRING* pASN1Str = subjectEntry->value; + + unsigned char* pData = NULL; + int nLength = ASN1_STRING_to_UTF8(&pData, + pASN1Str); + + if (nLength < 0) { + LogError("Reading field error."); + ThrowMsg(Exception::OpensslInternalError, + "Reading field error."); + } + + std::string strEntry(reinterpret_cast(pData), + nLength); + output = DPL::FromUTF8String(strEntry); + OPENSSL_free(pData); + } + return output; +} + +DPL::OptionalString Certificate::getCommonName(FieldType type) const +{ + return getField(type, NID_commonName); +} + +DPL::OptionalString Certificate::getCountryName(FieldType type) const +{ + return getField(type, NID_countryName); +} + +DPL::OptionalString Certificate::getStateOrProvinceName(FieldType type) const +{ + return getField(type, NID_stateOrProvinceName); +} + +DPL::OptionalString Certificate::getLocalityName(FieldType type) const +{ + return getField(type, NID_localityName); +} + +DPL::OptionalString Certificate::getOrganizationName(FieldType type) const +{ + return getField(type, NID_organizationName); +} + +DPL::OptionalString Certificate::getOrganizationalUnitName(FieldType type) const +{ + return getField(type, NID_organizationalUnitName); +} + +DPL::OptionalString Certificate::getOCSPURL() const +{ + // TODO verify this code + DPL::OptionalString retValue; + AUTHORITY_INFO_ACCESS *aia = static_cast( + X509_get_ext_d2i(m_x509, + NID_info_access, + NULL, + NULL)); + + // no AIA extension in the cert + if (NULL == aia) { + return retValue; + } + + int count = sk_ACCESS_DESCRIPTION_num(aia); + + for (int i = 0; i < count; ++i) { + ACCESS_DESCRIPTION* ad = sk_ACCESS_DESCRIPTION_value(aia, i); + + if (OBJ_obj2nid(ad->method) == NID_ad_OCSP && + ad->location->type == GEN_URI) + { + void* data = ASN1_STRING_data(ad->location->d.ia5); + retValue = DPL::OptionalString(DPL::FromUTF8String( + static_cast(data))); + + break; + } + } + sk_ACCESS_DESCRIPTION_free(aia); + return retValue; +} + +Certificate::AltNameSet Certificate::getAlternativeNameDNS() const +{ + AltNameSet set; + + GENERAL_NAME *namePart = NULL; + + STACK_OF(GENERAL_NAME)* san = + static_cast( + X509_get_ext_d2i(m_x509,NID_subject_alt_name,NULL,NULL)); + + while (sk_GENERAL_NAME_num(san) > 0) { + namePart = sk_GENERAL_NAME_pop(san); + if (GEN_DNS == namePart->type) { + std::string temp = + reinterpret_cast(ASN1_STRING_data(namePart->d.dNSName)); + DPL::String altDNSName = DPL::FromASCIIString(temp); + set.insert(altDNSName); + LogDebug("FOUND GEN_DNS: " << temp); + } else { + LogDebug("FOUND GEN TYPE ID: " << namePart->type); + } + } + return set; +} + +time_t Certificate::getNotAfter() const +{ + ASN1_TIME *time = X509_get_notAfter(m_x509); + if (!time) { + LogError("Reading Not After error."); + ThrowMsg(Exception::OpensslInternalError, "Reading Not After error."); + } + time_t output; + if (asn1TimeToTimeT(time, &output)) { + LogError("Converting ASN1_time to time_t error."); + ThrowMsg(Exception::OpensslInternalError, + "Converting ASN1_time to time_t error."); + } + return output; +} + +time_t Certificate::getNotBefore() const +{ + ASN1_TIME *time = X509_get_notBefore(m_x509); + if (!time) { + LogError("Reading Not Before error."); + ThrowMsg(Exception::OpensslInternalError, "Reading Not Before error."); + } + time_t output; + if (asn1TimeToTimeT(time, &output)) { + LogError("Converting ASN1_time to time_t error."); + ThrowMsg(Exception::OpensslInternalError, + "Converting ASN1_time to time_t error."); + } + return output; +} + +bool Certificate::isRootCert() +{ + // based on that root certificate has the same subject as issuer name + return isSignedBy(this->SharedFromThis()); +} + +std::list +Certificate::getCrlUris() const +{ + std::list result; + + STACK_OF(DIST_POINT)* distPoints = + static_cast( + X509_get_ext_d2i( + getX509(), + NID_crl_distribution_points, + NULL, + NULL)); + if (!distPoints) { + LogDebug("No distribution points in certificate."); + return result; + } + + int count = sk_DIST_POINT_num(distPoints); + for (int i = 0; i < count; ++i) { + DIST_POINT* point = sk_DIST_POINT_value(distPoints, i); + if (!point) { + LogError("Failed to get distribution point."); + continue; + } + if (point->distpoint != NULL && + point->distpoint->name.fullname != NULL) + { + int countName = + sk_GENERAL_NAME_num(point->distpoint->name.fullname); + for (int j = 0; j < countName; ++j) { + GENERAL_NAME* name = sk_GENERAL_NAME_value( + point->distpoint->name.fullname, j); + if (name != NULL && GEN_URI == name->type) { + char *crlUri = + reinterpret_cast(name->d.ia5->data); + if (!crlUri) { + LogError("Failed to get URI."); + continue; + } + result.push_back(crlUri); + } + } + } + } + sk_DIST_POINT_pop_free(distPoints, DIST_POINT_free); + return result; +} + +long Certificate::getVersion() const +{ + return X509_get_version(m_x509); +} + +DPL::String Certificate::getSerialNumberString() const +{ + ASN1_INTEGER *ai = X509_get_serialNumber(m_x509); + if (NULL == ai) { + LogError("Error in X509_get_serialNumber"); + ThrowMsg(Exception::OpensslInternalError, + "Error in X509_get_serialNumber"); + } + std::stringstream stream; + stream << std::hex << std::setfill('0'); + if (ai->type == V_ASN1_NEG_INTEGER) { + stream << "(Negetive) "; + } + for (int i=0; ilength; ++i) { + stream << std::setw(2) << (int)ai->data[i] << ":"; + } + std::string data = stream.str(); + if (!data.empty()) { + data.erase(--data.end()); + } + return DPL::FromUTF8String(data); +} + +DPL::String Certificate::getKeyUsageString() const +{ + // Extensions were defined in RFC 3280 + const char *usage[] = { + "digitalSignature", + "nonRepudiation", + "keyEncipherment", + "dataEncipherment", + "keyAgreement", + "keyCertSign", + "cRLSign", + "encipherOnly", + "decipherOnly" + }; + int crit = -1; + int idx = -1; + ASN1_BIT_STRING *keyUsage = (ASN1_BIT_STRING*) + X509_get_ext_d2i(m_x509, NID_key_usage, &crit, &idx); + + std::stringstream stream; + for(int i=0; i<9; ++i) { + if (ASN1_BIT_STRING_get_bit(keyUsage, i)) { + stream << usage[i] << ","; + } + } + std::string result = stream.str(); + if (!result.empty()) { + result.erase(--result.end()); + } + return DPL::FromUTF8String(result); +} + +DPL::String Certificate::getSignatureAlgorithmString() const +{ + std::unique_ptr> + b(BIO_new(BIO_s_mem()),BIO_free); + + if (b.get() == NULL) { + LogError("Error in BIO_new"); + ThrowMsg(Exception::OpensslInternalError, + "Error in BIO_new"); + } + if (i2a_ASN1_OBJECT(b.get(), m_x509->cert_info->signature->algorithm) < 0) { + LogError("Error in i2a_ASN1_OBJECT"); + ThrowMsg(Exception::OpensslInternalError, + "Error in i2a_ASN1_OBJECT"); + } + BUF_MEM *bptr = 0; + BIO_get_mem_ptr(b.get(), &bptr); + if (bptr == 0) { + LogError("Error in BIO_get_mem_ptr"); + ThrowMsg(Exception::OpensslInternalError, + "Error in BIO_get_mem_ptr"); + } + std::string result(bptr->data, bptr->length); + return DPL::FromUTF8String(result); +} + +DPL::String Certificate::getPublicKeyString() const +{ + std::unique_ptr> + b(BIO_new(BIO_s_mem()),BIO_free); + + if (b.get() == NULL) { + LogError("Error in BIO_new"); + ThrowMsg(Exception::OpensslInternalError, + "Error in BIO_new"); + } + EVP_PKEY *pkey = X509_get_pubkey(m_x509); + if (pkey == NULL) { + LogError("Error in X509_get_pubkey"); + ThrowMsg(Exception::OpensslInternalError, + "Error in X509_get_pubkey"); + } + EVP_PKEY_print_public(b.get(), pkey, 16, NULL); + EVP_PKEY_free(pkey); + + BUF_MEM *bptr = 0; + BIO_get_mem_ptr(b.get(), &bptr); + if (bptr == 0) { + LogError("Error in BIO_get_mem_ptr"); + ThrowMsg(Exception::OpensslInternalError, + "Error in BIO_get_mem_ptr"); + } + std::string result(bptr->data, bptr->length); + return DPL::FromUTF8String(result); +} + +} // namespace ValidationCore diff --git a/vcore/src/vcore/Certificate.h b/vcore/src/vcore/Certificate.h new file mode 100644 index 0000000..b63f113 --- /dev/null +++ b/vcore/src/vcore/Certificate.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2011 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 Certificate.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.1 + * @brief + */ +#ifndef _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_CERTIFICATE_H_ +#define _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_CERTIFICATE_H_ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace ValidationCore { + +// from OpenSSL asn1/a_utctm.c code +int asn1TimeToTimeT(ASN1_TIME *t, + time_t *res); + + +int asn1GeneralizedTimeToTimeT(ASN1_GENERALIZEDTIME *tm, + time_t *res); + +class Certificate; + +typedef DPL::SharedPtr CertificatePtr; +typedef std::list CertificateList; + +class Certificate : public DPL::EnableSharedFromThis +{ + public: + typedef std::vector Fingerprint; + typedef DPL::String AltName; + typedef std::set AltNameSet; + + enum FingerprintType + { + FINGERPRINT_MD5, + FINGERPRINT_SHA1 + }; + enum FieldType + { + FIELD_ISSUER, + FIELD_SUBJECT + }; + + enum FormType + { + FORM_DER, + FORM_BASE64 + }; + + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, OpensslInternalError) + }; + + explicit Certificate(X509 *cert); + + explicit Certificate(cert_svc_mem_buff &buffer); + + explicit Certificate(const std::string &der, + FormType form = FORM_DER); + + ~Certificate(); + + // It returns pointer to internal structure! + // Do not free this pointer! + X509 *getX509(void) const; + + std::string getDER(void) const; + + std::string getBase64(void) const; + + // This const is cheating here because you have no + // guarantee that X509_get_subject_name will not + // change X509 object. + bool isSignedBy(const CertificatePtr &parent) const; + + Fingerprint getFingerprint(FingerprintType type) const; + + // getName uses deprecated functions. Usage is strongly discouraged. + DPL::String getOneLine(FieldType type = FIELD_SUBJECT) const; + DPL::OptionalString getCommonName(FieldType type = FIELD_SUBJECT) const; + DPL::OptionalString getCountryName(FieldType type = FIELD_SUBJECT) const; + DPL::OptionalString getStateOrProvinceName( + FieldType type = FIELD_SUBJECT) const; + DPL::OptionalString getLocalityName(FieldType type = FIELD_SUBJECT) const; + DPL::OptionalString getOrganizationName( + FieldType type = FIELD_SUBJECT) const; + DPL::OptionalString getOrganizationalUnitName( + FieldType type = FIELD_SUBJECT) const; + DPL::OptionalString getOCSPURL() const; + + // Openssl supports 9 types of alternative name filed. + // 4 of them are "string similar" types so it is possible + // to create more generic function. + AltNameSet getAlternativeNameDNS() const; + + time_t getNotAfter() const; + + time_t getNotBefore() const; + + /** + * @brief This is convenient function. + * + * @details It can't be const function (however it doesn't change internal + * object). For details see #isSignedBy() function description. + */ + bool isRootCert(); + + /** + * @brief Gets list of CRL distribution's points URIs + */ + std::list getCrlUris() const; + + long getVersion() const; + + DPL::String getSerialNumberString() const; + + DPL::String getKeyUsageString() const; + + DPL::String getSignatureAlgorithmString() const; + + DPL::String getPublicKeyString() const; + + protected: + X509_NAME *getX509Name(FieldType type) const; + + DPL::OptionalString getField(FieldType type, + int fieldNid) const; + + X509 *m_x509; +}; +} // namespace ValidationCore + +#endif diff --git a/vcore/src/vcore/CertificateCacheDAO.cpp b/vcore/src/vcore/CertificateCacheDAO.cpp new file mode 100644 index 0000000..04956a3 --- /dev/null +++ b/vcore/src/vcore/CertificateCacheDAO.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2011 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 CertificateCacheDAO.cpp + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 0.1 + * @brief CertificateCacheDAO implementation + */ + +#include "CertificateCacheDAO.h" +#include "VCorePrivate.h" + +#include +#include +#include +#include +#include + +using namespace DPL::DB::ORM; +using namespace DPL::DB::ORM::vcore; + +namespace ValidationCore { + +void CertificateCacheDAO::setOCSPStatus(const std::string& cert_chain, + VerificationStatus ocsp_status, + bool end_entity_check, + time_t next_update_time) +{ + Try { + ScopedTransaction transaction(&ThreadInterface()); + OCSPCachedStatus status; + status.cert_chain = cert_chain; + status.end_entity_check = end_entity_check; + if (getOCSPStatus(&status)) { + // only need to update data in DB + Equals e1( + DPL::FromUTF8String(cert_chain)); + Equals e2( + end_entity_check ? 1 : 0); + + OCSPResponseStorage::Row row; + + row.Set_ocsp_status(ocsp_status); + row.Set_next_update_time(next_update_time); + + VCORE_DB_UPDATE(update, OCSPResponseStorage, &ThreadInterface()) + update->Where(And(e1,e2)); + update->Values(row); + update->Execute(); + } else { + // need to insert data + OCSPResponseStorage::Row row; + + row.Set_cert_chain(DPL::FromUTF8String(cert_chain)); + row.Set_ocsp_status(ocsp_status); + row.Set_next_update_time(next_update_time); + row.Set_end_entity_check(end_entity_check ? 1 : 0); + + VCORE_DB_INSERT(insert, OCSPResponseStorage, &ThreadInterface()) + insert->Values(row); + insert->Execute(); + } + transaction.Commit(); + } Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(Exception::DatabaseError, "Failed to setOCSPStatus"); + } +} + +bool CertificateCacheDAO::getOCSPStatus(OCSPCachedStatus* cached_status) +{ + if (NULL == cached_status) { + LogError("NULL pointer"); + return false; + } + Try { + Equals e1( + DPL::FromUTF8String(cached_status->cert_chain)); + Equals e2( + cached_status->end_entity_check ? 1 : 0); + + VCORE_DB_SELECT(select, OCSPResponseStorage, &ThreadInterface()) + + select->Where(And(e1,e2)); + std::list rows = select->GetRowList(); + if (1 == rows.size()) { + OCSPResponseStorage::Row row = rows.front(); + cached_status->ocsp_status = intToVerificationStatus( + *(row.Get_ocsp_status())); + cached_status->next_update_time = *(row.Get_next_update_time()); + return true; + } + + LogDebug("Cached OCSP status not found"); + return false; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(Exception::DatabaseError, "Failed to getOCSPStatus"); + } +} + +void CertificateCacheDAO::getOCSPStatusList( + OCSPCachedStatusList* cached_status_list) +{ + if (NULL == cached_status_list) { + LogError("NULL pointer"); + return; + } + Try { + VCORE_DB_SELECT(select, OCSPResponseStorage, &ThreadInterface()) + typedef std::list RowList; + RowList list = select->GetRowList(); + + FOREACH(i, list) { + OCSPCachedStatus status; + status.cert_chain = DPL::ToUTF8String(i->Get_cert_chain()); + status.ocsp_status = intToVerificationStatus( + *(i->Get_ocsp_status())); + status.end_entity_check = + *(i->Get_end_entity_check()) == 1 ? true : false; + status.next_update_time = *(i->Get_next_update_time()); + cached_status_list->push_back(status); + } + + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(Exception::DatabaseError, "Failed to getOCSPStatusList"); + } +} + + +void CertificateCacheDAO::setCRLResponse(const std::string& distribution_point, + const std::string& crl_body, + time_t next_update_time) +{ + Try { + ScopedTransaction transaction(&ThreadInterface()); + CRLCachedData data; + data.distribution_point = distribution_point; + if (getCRLResponse(&data)) { + // only need to update data in DB + VCORE_DB_UPDATE(update, CRLResponseStorage, &ThreadInterface()) + Equals e1( + DPL::FromUTF8String(distribution_point)); + CRLResponseStorage::Row row; + + update->Where(e1); + row.Set_crl_body(DPL::FromUTF8String(crl_body)); + row.Set_next_update_time(next_update_time); + update->Values(row); + update->Execute(); + } else { + // need to insert data + VCORE_DB_INSERT(insert, CRLResponseStorage, &ThreadInterface()) + CRLResponseStorage::Row row; + + row.Set_distribution_point(DPL::FromUTF8String(distribution_point)); + row.Set_crl_body(DPL::FromUTF8String(crl_body)); + row.Set_next_update_time(next_update_time); + insert->Values(row); + insert->Execute(); + } + transaction.Commit(); + } Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(Exception::DatabaseError, "Failed to setOCSPStatus"); + } +} + +bool CertificateCacheDAO::getCRLResponse(CRLCachedData* cached_data) +{ + if (NULL == cached_data) { + LogError("NULL pointer"); + return false; + } + Try { + VCORE_DB_SELECT(select, CRLResponseStorage, &ThreadInterface()) + Equals e1( + DPL::FromUTF8String(cached_data->distribution_point)); + + select->Where(e1); + std::list rows = select->GetRowList(); + if (1 == rows.size()) { + CRLResponseStorage::Row row = rows.front(); + cached_data->crl_body = DPL::ToUTF8String(row.Get_crl_body()); + cached_data->next_update_time = *(row.Get_next_update_time()); + return true; + } + + LogDebug("Cached CRL not found"); + return false; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(Exception::DatabaseError, "Failed to getCRLResponse"); + } +} + +void CertificateCacheDAO::getCRLResponseList( + CRLCachedDataList* cached_data_list) +{ + if (NULL == cached_data_list) { + LogError("NULL pointer"); + return; + } + Try { + VCORE_DB_SELECT(select, CRLResponseStorage, &ThreadInterface()) + typedef std::list RowList; + RowList list = select->GetRowList(); + + FOREACH(i, list) { + CRLCachedData response; + response.distribution_point = DPL::ToUTF8String( + i->Get_distribution_point()); + response.crl_body = DPL::ToUTF8String(i->Get_crl_body()); + response.next_update_time = *(i->Get_next_update_time()); + cached_data_list->push_back(response); + } + + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(Exception::DatabaseError, "Failed to getCRLResponses"); + } +} + +void CertificateCacheDAO::clearCertificateCache() +{ + Try { + ScopedTransaction transaction(&ThreadInterface()); + VCORE_DB_DELETE(del1, OCSPResponseStorage, &ThreadInterface()) + del1->Execute(); + VCORE_DB_DELETE(del2, CRLResponseStorage, &ThreadInterface()) + del2->Execute(); + transaction.Commit(); + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(Exception::DatabaseError, "Failed to clearUserSettings"); + } +} + +VerificationStatus CertificateCacheDAO::intToVerificationStatus(int p) +{ + switch (p) { + case 1: + return VERIFICATION_STATUS_GOOD; + case 1 << 1: + return VERIFICATION_STATUS_REVOKED; + case 1 << 2: + return VERIFICATION_STATUS_UNKNOWN; + case 1 << 3: + return VERIFICATION_STATUS_VERIFICATION_ERROR; + case 1 << 4: + return VERIFICATION_STATUS_NOT_SUPPORT; + case 1 << 5: + return VERIFICATION_STATUS_CONNECTION_FAILED; + case 1 << 6: + return VERIFICATION_STATUS_ERROR; + default: + return VERIFICATION_STATUS_ERROR; + } +} + +} // namespace ValidationCore diff --git a/vcore/src/vcore/CertificateCacheDAO.h b/vcore/src/vcore/CertificateCacheDAO.h new file mode 100644 index 0000000..c3daf3f --- /dev/null +++ b/vcore/src/vcore/CertificateCacheDAO.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2011 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 CertificateCacheDAO.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 0.1 + * @brief Header file for class managing CRL and OCSP cached responses + */ + +#ifndef _WRT_SRC_CONFIGURATION_CERTIFICATE_CACHE_DAO_H_ +#define _WRT_SRC_CONFIGURATION_CERTIFICATE_CACHE_DAO_H_ + +#include +#include + +#include + +#include "VerificationStatus.h" +#include "CRLCacheInterface.h" + +namespace ValidationCore { + +struct OCSPCachedStatus +{ + std::string cert_chain; + VerificationStatus ocsp_status; + bool end_entity_check; + time_t next_update_time; +}; + +typedef std::list OCSPCachedStatusList; + +typedef std::list CRLCachedDataList; + +class CertificateCacheDAO { + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DatabaseError) + }; + + // OCSP statuses + + static void setOCSPStatus(const std::string& cert_chain, + VerificationStatus ocsp_status, + bool end_entity_check, + time_t next_update_time); + + /* + * fill cert_chain and end_entity_check in cached_status + * returns true iff cached status found without errors + */ + static bool getOCSPStatus(OCSPCachedStatus* cached_status); + static void getOCSPStatusList(OCSPCachedStatusList* cached_status_list); + + // CRL responses + + static void setCRLResponse(const std::string& distribution_point, + const std::string& crl_body, + time_t next_update_time); + static void setCRLResponse(CRLCachedData *ptr) { + setCRLResponse( + ptr->distribution_point, + ptr->crl_body, + ptr->next_update_time); + } + /* + * fill distribution_point + * returns true iff cached list for dist. point found without errors + */ + static bool getCRLResponse(CRLCachedData* cached_data); + static void getCRLResponseList(CRLCachedDataList* cached_data_list); + + + // clears CRL and OCSP cached data + static void clearCertificateCache(); + + private: + + static VerificationStatus intToVerificationStatus(int p); + + CertificateCacheDAO() + { + } +}; + +} // namespace ValidationCore + +#endif /* _WRT_SRC_CONFIGURATION_CERTIFICATE_CACHE_DAO_H_ */ diff --git a/vcore/src/vcore/CertificateCollection.cpp b/vcore/src/vcore/CertificateCollection.cpp new file mode 100644 index 0000000..3e9edc3 --- /dev/null +++ b/vcore/src/vcore/CertificateCollection.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2011 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. + */ +#include + +#include + +#include +#include +#include + +#include + +namespace { +using namespace ValidationCore; + +inline std::string toBinaryString(int data) +{ + char buffer[sizeof(int)]; + memcpy(buffer, &data, sizeof(int)); + return std::string(buffer, buffer + sizeof(int)); +} +} // namespace + +namespace ValidationCore { +CertificateCollection::CertificateCollection() : + m_collectionStatus(COLLECTION_UNSORTED) +{ +} + +void CertificateCollection::clear(void) +{ + m_collectionStatus = COLLECTION_UNSORTED; + m_certList.clear(); +} + +void CertificateCollection::load(const CertificateList &certList) +{ + m_collectionStatus = COLLECTION_UNSORTED; + std::copy(certList.begin(), + certList.end(), + std::back_inserter(m_certList)); +} + +bool CertificateCollection::load(const std::string &buffer) +{ + Base64Decoder base64; + base64.reset(); + base64.append(buffer); + if (!base64.finalize()) { + LogWarning("Error during chain decoding"); + return false; + } + std::string binaryData = base64.get(); + + DPL::BinaryQueue queue; + queue.AppendCopy(binaryData.c_str(), binaryData.size()); + + int certNum; + queue.FlattenConsume(&certNum, sizeof(int)); + + CertificateList list; + + for (int i = 0; i < certNum; ++i) { + int certSize; + queue.FlattenConsume(&certSize, sizeof(int)); + std::vector rawDERCert; + rawDERCert.resize(certSize); + queue.FlattenConsume(&rawDERCert[0], certSize); + Try { + list.push_back(CertificatePtr( + new Certificate(std::string(rawDERCert.begin(), + rawDERCert.end())))); + } Catch(Certificate::Exception::Base) { + LogWarning("Error during certificate creation."); + return false; + } + LogDebug("Loading certificate. Certificate common name: " << + list.back()->getCommonName()); + } + load(list); + return true; +} + +std::string CertificateCollection::toBase64String() const +{ + std::ostringstream output; + int certNum = m_certList.size(); + output << toBinaryString(certNum); + FOREACH(i, m_certList){ + std::string derCert = (*i)->getDER(); + output << toBinaryString(derCert.size()); + output << derCert; + } + Base64Encoder base64; + base64.reset(); + base64.append(output.str()); + base64.finalize(); + return base64.get(); +} + +CertificateList CertificateCollection::getCertificateList() const +{ + return m_certList; +} + +bool CertificateCollection::isChain() const +{ + if (COLLECTION_SORTED != m_collectionStatus) { + LogError("You must sort certificates first"); + ThrowMsg(Exception::WrongUsage, + "You must sort certificates first"); + } + return (COLLECTION_SORTED == m_collectionStatus) ? true : false; +} + +bool CertificateCollection::sort() +{ + if (COLLECTION_UNSORTED == m_collectionStatus) { + sortCollection(); + } + return (COLLECTION_SORTED == m_collectionStatus) ? true : false; +} + +CertificateList CertificateCollection::getChain() const +{ + if (COLLECTION_SORTED != m_collectionStatus) { + LogError("You must sort certificates first"); + ThrowMsg(Exception::WrongUsage, + "You must sort certificates first"); + } + return m_certList; +} + +void CertificateCollection::sortCollection() +{ + // sorting is not necessary + if (m_certList.empty()) { + m_collectionStatus = COLLECTION_SORTED; + return; + } + + CertificateList sorted; + std::map subTransl; + std::map issTransl; + + // Sort all certificate by subject + for (auto it = m_certList.begin(); it != m_certList.end(); ++it) { + subTransl.insert(std::make_pair(DPL::ToUTF8String((*it)->getOneLine()),(*it))); + } + // We need one start certificate + sorted.push_back(subTransl.begin()->second); + subTransl.erase(subTransl.begin()); + + // Get the issuer from front certificate and find certificate with this subject in subTransl. + // Add this certificate to the front. + while (!subTransl.empty()) { + std::string issuer = DPL::ToUTF8String(sorted.back()->getOneLine(Certificate::FIELD_ISSUER)); + auto it = subTransl.find(issuer); + if (it == subTransl.end()) { + break; + } + sorted.push_back(it->second); + subTransl.erase(it); + } + + // Sort all certificates by issuer + for (auto it = subTransl.begin(); it != subTransl.end(); ++it) { + issTransl.insert(std::make_pair(DPL::ToUTF8String((it->second->getOneLine(Certificate::FIELD_ISSUER))),it->second)); + } + + // Get the subject from last certificate and find certificate with such issuer in issTransl. + // Add this certificate at end. + while (!issTransl.empty()) { + std::string sub = DPL::ToUTF8String(sorted.front()->getOneLine()); + auto it = issTransl.find(sub); + if (it == issTransl.end()) { + break; + } + sorted.push_front(it->second); + issTransl.erase(it); + } + + if (!issTransl.empty()) { + LogWarning("Certificates don't form a valid chain."); + m_collectionStatus = COLLECTION_CHAIN_BROKEN; + return; + } + + m_collectionStatus = COLLECTION_SORTED; + m_certList = sorted; +} + +} // namespace ValidationCore + diff --git a/vcore/src/vcore/CertificateCollection.h b/vcore/src/vcore/CertificateCollection.h new file mode 100644 index 0000000..78b4737 --- /dev/null +++ b/vcore/src/vcore/CertificateCollection.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2011 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. + */ +#ifndef _WRT_ENGINE_SRC_VALIDATION_CORE_CERTIFICATECOLLECTION_H_ +#define _WRT_ENGINE_SRC_VALIDATION_CORE_CERTIFICATECOLLECTION_H_ + +#include +#include + +#include + +#include + +namespace ValidationCore { +/* + * This class is used to store Certificate Chain. + * It could serialize chain to std::string in base64 form. + * It could read chain written in base64 form. + * It could check if collection creates certificate chain. + */ + +class CertificateCollection +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, WrongUsage) + }; + + CertificateCollection(); + + typedef CertificateList::const_iterator const_iterator; + + /* + * Remove all certificates from collection. + */ + void clear(); + + /* + * In current implemenation this function MUST success. + * + * This function will add new certificate to collection. + * This function DOES NOT clean collection. + */ + void load(const CertificateList &certList); + + /* + * This function will return false if base64 string is broken + * (is not encoded in base64 format) or one from certificate + * is broken (is not encoded in der format). + * + * This function will add new certificate to collection. + * This function DOES NOT clean collection. + */ + bool load(const std::string &base64); + + /* + * This function will return all certificates from + * collection encoded in base64 format. + */ + std::string toBase64String() const; + + /* + * This will return all certificate from collection. + */ + CertificateList getCertificateList() const; + + /* + * This function will return true if certificates + * in in this structure were sorted and create + * certificate chain. + + * Note: You MUST sort certificates first. + */ + bool isChain() const; + + /* + * This function will return true if all certificate are + * able to create certificate chain. + * + * This function will sort certificates if collection + * is not sorted. + * + * Note: This function will make all iterators invalid. + */ + bool sort(); + + /* + * This function will return Certificate chain. + * + * First certificate on the list is EndEntity certificate. + * + * Last certificate on the list is RootCA certificate or + * CA certificate if RootCA is not present. + * + * Note: You MUST sort certificates first and + * check if certificates creates proper chain. + */ + CertificateList getChain() const; + + /* + * It returns size of certificate collection. + */ + inline size_t size() const + { + return m_certList.size(); + } + + /* + * Return true if collection is empty. + */ + inline bool empty() const + { + return m_certList.empty(); + } + + /* + * This will return end iterator to internal collection. + * + * Note: this iterator will lose validity if you call non const + * method on CertificateCollection class. + */ + inline const_iterator begin() const + { + return m_certList.begin(); + } + + /* + * This will return end iterator to internal collection. + * + * Note: this iterator will lose validity if you call non const + * method on CertificateCollection class. + */ + inline const_iterator end() const + { + return m_certList.end(); + } + + /* + * This function will return the last certificate from collection. + * + * Note: There is no point to call this function if certificate + * collection is not sorted! + */ + inline CertificatePtr back() const + { + return m_certList.back(); + } + + protected: + void sortCollection(void); + + enum CollectionStatus + { + // Certificate collection are not sorted in any way + COLLECTION_UNSORTED, + // Certificate collection creates certificate chain + COLLECTION_SORTED, + // Cerfificate collection is not able to create certificate chain + COLLECTION_CHAIN_BROKEN, + }; + + CollectionStatus m_collectionStatus; + CertificateList m_certList; +}; + +typedef std::list CertificateCollectionList; +} // namespace ValidationCore + +#endif // _WRT_ENGINE_SRC_VALIDATION_CORE_CERTIFICATECHAIN_H_ diff --git a/vcore/src/vcore/CertificateConfigReader.cpp b/vcore/src/vcore/CertificateConfigReader.cpp new file mode 100644 index 0000000..2a61940 --- /dev/null +++ b/vcore/src/vcore/CertificateConfigReader.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2011 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 + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ +#include "CertificateConfigReader.h" + +#include + +#include + +namespace { +const std::string XML_EMPTY_NAMESPACE = ""; + +const std::string TOKEN_CERTIFICATE_SET = "CertificateSet"; +const std::string TOKEN_CERTIFICATE_DOMAIN = "CertificateDomain"; +const std::string TOKEN_FINGERPRINT_SHA1 = "FingerprintSHA1"; + +const std::string TOKEN_ATTR_NAME = "name"; +const std::string TOKEN_VALUE_WAC_ROOT = "wacroot"; +const std::string TOKEN_VALUE_WAC_PUBLISHER = "wacpublisher"; +const std::string TOKEN_VALUE_WAC_MEMBER = "wacmember"; +const std::string TOKEN_VALUE_DEVELOPER = "developer"; + +int hexCharToInt(char c) +{ + if (c >= 'a' && c <= 'f') { + return 10 + static_cast(c) - 'a'; + } + if (c >= 'A' && c <= 'F') { + return 10 + static_cast(c) - 'A'; + } + if (c >= '0' && c <= '9') { + return static_cast(c) - '0'; + } + return c; +} +} // anonymous namespace + +namespace ValidationCore { +CertificateConfigReader::CertificateConfigReader() : + m_certificateDomain(0), + m_parserSchema(this) +{ + m_parserSchema.addBeginTagCallback( + TOKEN_CERTIFICATE_SET, + XML_EMPTY_NAMESPACE, + &CertificateConfigReader::blankFunction); + + m_parserSchema.addBeginTagCallback( + TOKEN_CERTIFICATE_DOMAIN, + XML_EMPTY_NAMESPACE, + &CertificateConfigReader::tokenCertificateDomain); + + m_parserSchema.addBeginTagCallback( + TOKEN_FINGERPRINT_SHA1, + XML_EMPTY_NAMESPACE, + &CertificateConfigReader::blankFunction); + + m_parserSchema.addEndTagCallback( + TOKEN_CERTIFICATE_SET, + XML_EMPTY_NAMESPACE, + &CertificateConfigReader::blankFunction); + + m_parserSchema.addEndTagCallback( + TOKEN_CERTIFICATE_DOMAIN, + XML_EMPTY_NAMESPACE, + &CertificateConfigReader::blankFunction); + + m_parserSchema.addEndTagCallback( + TOKEN_FINGERPRINT_SHA1, + XML_EMPTY_NAMESPACE, + &CertificateConfigReader::tokenEndFingerprintSHA1); +} + +void CertificateConfigReader::tokenCertificateDomain(CertificateIdentifier &) +{ + std::string name = m_parserSchema.getReader(). + attribute(TOKEN_ATTR_NAME, SaxReader::THROW_DISABLE); + + if (name.empty()) { + LogWarning("Invalid fingerprint file. Domain name is mandatory"); + ThrowMsg(Exception::InvalidFile, + "Invalid fingerprint file. Domain name is mandatory"); + } else if (name == TOKEN_VALUE_DEVELOPER) { + m_certificateDomain = CertStoreId::DEVELOPER; + } else if (name == TOKEN_VALUE_WAC_ROOT) { + m_certificateDomain = CertStoreId::WAC_ROOT; + } else if (name == TOKEN_VALUE_WAC_PUBLISHER) { + m_certificateDomain = CertStoreId::WAC_PUBLISHER; + } else if (name == TOKEN_VALUE_WAC_MEMBER) { + m_certificateDomain = CertStoreId::WAC_MEMBER; + } +} + +void CertificateConfigReader::tokenEndFingerprintSHA1( + CertificateIdentifier &identificator) +{ + std::string text = m_parserSchema.getText(); + text += ":"; // add guard at the end of fingerprint + Certificate::Fingerprint fingerprint; + int s = 0; + int byteDescLen = 0; + for (size_t i = 0; i < text.size(); ++i) { + if (isxdigit(text[i])) { + s <<= 4; + s += hexCharToInt(text[i]); + byteDescLen++; + if (byteDescLen > 2) { + Assert(0 && "Unsupported fingerprint format in xml file."); + } + } else if (text[i] == ':') { + fingerprint.push_back(static_cast(s)); + s = 0; + byteDescLen = 0; + } else { + Assert(0 && "Unussported fingerprint format in xml file."); + } + } + identificator.add(fingerprint, m_certificateDomain); +} +} // namespace ValidationCore diff --git a/vcore/src/vcore/CertificateConfigReader.h b/vcore/src/vcore/CertificateConfigReader.h new file mode 100644 index 0000000..92e000e --- /dev/null +++ b/vcore/src/vcore/CertificateConfigReader.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011 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 + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ +#ifndef \ + _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_CERTIFICATE_CONFIG_READER_H_ +#define \ + _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_CERTIFICATE_CONFIG_READER_H_ + +#include +#include + +#include "CertificateIdentifier.h" +#include "CertStoreType.h" +#include "ParserSchema.h" + +namespace ValidationCore { +class CertificateConfigReader +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, InvalidFile) + }; + CertificateConfigReader(); + + void initialize(const std::string &file, + const std::string &scheme) + { + m_parserSchema.initialize(file, true, SaxReader::VALIDATION_XMLSCHEME, + scheme); + } + + void read(CertificateIdentifier &identificator) + { + m_parserSchema.read(identificator); + } + + private: + void blankFunction(CertificateIdentifier &) + { + } + void tokenCertificateDomain(CertificateIdentifier &identificator); + void tokenEndFingerprintSHA1(CertificateIdentifier &identificator); + + CertStoreId::Type m_certificateDomain; + ParserSchema + m_parserSchema; +}; +} // namespace ValidationCore + +#endif // _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_CERTIFICATE_CONFIG_READER_H_ diff --git a/vcore/src/vcore/CertificateIdentifier.h b/vcore/src/vcore/CertificateIdentifier.h new file mode 100644 index 0000000..f9ed48c --- /dev/null +++ b/vcore/src/vcore/CertificateIdentifier.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 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 + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ +#ifndef \ + _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_CERTIFICATEIDENTIFICATOR_H_ +#define \ + _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_CERTIFICATEIDENTIFICATOR_H_ + +#include + +#include + +#include "Certificate.h" +#include "CertStoreType.h" + +namespace ValidationCore { +class CertificateIdentifier : public DPL::Noncopyable +{ + public: + typedef std::map FingerPrintMap; + + CertificateIdentifier() + { + } + ~CertificateIdentifier() + { + } + + void add(const Certificate::Fingerprint &fingerprint, + CertStoreId::Type domain) + { + fingerPrintMap[fingerprint].add(domain); + } + + CertStoreId::Set find(const Certificate::Fingerprint &fingerprint) const + { + FingerPrintMap::const_iterator iter = fingerPrintMap.find(fingerprint); + if (iter == fingerPrintMap.end()) { + return CertStoreId::Set(); + } + return iter->second; + } + + CertStoreId::Set find(const CertificatePtr &certificate) const + { + return + find(certificate->getFingerprint(Certificate::FINGERPRINT_SHA1)); + } + + private: + FingerPrintMap fingerPrintMap; +}; +} // namespace ValidationCore + +#endif // _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_CERTIFICATEIDENTIFICATOR_H_ diff --git a/vcore/src/vcore/CertificateLoader.cpp b/vcore/src/vcore/CertificateLoader.cpp new file mode 100644 index 0000000..b7af557 --- /dev/null +++ b/vcore/src/vcore/CertificateLoader.cpp @@ -0,0 +1,718 @@ +/* + * Copyright (c) 2011 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. + */ +#include +#include +#include +#include +#include +#include + +#include "Base64.h" +#include "CertificateLoader.h" +#include "SSLContainers.h" + +namespace { +const int MIN_RSA_KEY_LENGTH = 1024; +//const char *OID_CURVE_SECP256R1 = "urn:oid:1.2.840.10045.3.1.7"; +} // namespace anonymous + +namespace ValidationCore { +//// COMPARATOR CLASS START //// + +//class CertificateLoaderECDSA : public CertificateLoader::CertificateLoaderComparator, DPL::Noncopyable { +//public: +// CertificateLoaderECDSA(const std::string &publicKey) +// : m_ecPublicKey(NULL) +// , m_searchKey(NULL) +// { +// m_bnCtx = BN_CTX_new(); // if fails we can continue anyway +// m_tmpPoint = BN_new(); // if fails we can continue anyway +// m_initialized = CertificateLoader::convertBase64NodeToBigNum(publicKey, &m_searchKey); +// +// if(!m_initialized) +// LogError("Init failed!"); +// } +// +// virtual bool compare(X509 *x509cert){ +// if(!m_initialized) +// return false; +// +// EVP_PKEY_free(m_ecPublicKey); +// +// m_ecPublicKey = X509_get_pubkey(x509cert); +// +// if(m_ecPublicKey == NULL) +// return false; +// +// if(m_ecPublicKey->type != EVP_PKEY_EC){ +// LogError("ecPublicKey has wrong type!"); +// return false; +// } +// +// // Pointer to internal data of ecPublicKey. Do not free! +// EC_KEY *eckey = m_ecPublicKey->pkey.ec; +// +// const EC_POINT *ecpoint = EC_KEY_get0_public_key(eckey); +// const EC_GROUP *ecgroup = EC_KEY_get0_group(eckey); +// +// m_tmpPoint = EC_POINT_point2bn(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, m_tmpPoint, m_bnCtx); +// +// if(BN_cmp(m_tmpPoint, m_searchKey) == 0) +// return true; +// +// return false; +// } +// +// ~CertificateLoaderECDSA(){ +// BN_CTX_free(m_bnCtx); +// EVP_PKEY_free(m_ecPublicKey); +// BN_free(m_searchKey); +// BN_free(m_tmpPoint); +// } +// +//private: +// bool m_initialized; +// EVP_PKEY *m_ecPublicKey; +// BN_CTX *m_bnCtx; +// BIGNUM *m_searchKey; +// BIGNUM *m_tmpPoint; +//}; + +///// COMPARETORS CLASS END ///// + +//// COMPARATOR RSA CLASS START //// + +//class CertificateLoaderRSA : public CertificateLoader::CertificateLoaderComparator, DPL::Noncopyable { +//public: +// CertificateLoaderRSA(const std::string &m_modulus,const std::string &m_exponent ) +// : m_rsaPublicKey(NULL) +// , m_modulus_bn(NULL) +// , m_exponent_bn(NULL) +// { +// +// m_initialized_modulus = CertificateLoader::convertBase64NodeToBigNum(m_modulus, &m_modulus_bn); +// m_initialized_exponent = CertificateLoader::convertBase64NodeToBigNum(m_exponent, &m_exponent_bn); +// +// if(!m_initialized_modulus || !m_initialized_exponent) +// LogError("Init failed!"); +// } +// +// virtual bool compare(X509 *x509cert){ +// +// if(!m_initialized_modulus || !m_initialized_exponent) +// return false; +// +// EVP_PKEY_free(m_rsaPublicKey); +// m_rsaPublicKey = X509_get_pubkey(x509cert); +// +// if(m_rsaPublicKey == NULL) +// return false; +// +// if(m_rsaPublicKey->type != EVP_PKEY_RSA){ +// LogInfo("rsaPublicKey has wrong type!"); +// return false; +// } +// +// RSA *rsa = NULL; +// rsa = m_rsaPublicKey->pkey.rsa; +// +// if (BN_cmp(m_modulus_bn, rsa->n) == 0 && +// BN_cmp(m_exponent_bn, rsa->e) == 0 ){ +// LogError ("Compare TRUE"); +// return true; +// } +// return false; +// } +// +// ~CertificateLoaderRSA(){ +// EVP_PKEY_free(m_rsaPublicKey); +// BN_free(m_modulus_bn); +// BN_free(m_exponent_bn); +// +// } +// +//private: +// bool m_initialized_modulus; +// bool m_initialized_exponent; +// EVP_PKEY *m_rsaPublicKey; +// BIGNUM *m_modulus_bn; +// BIGNUM *m_exponent_bn; +//}; + +///// COMPARETORS RSA CLASS END ///// + +CertificateLoader::CertificateLoaderResult CertificateLoader:: + loadCertificateBasedOnExponentAndModulus(const std::string &m_modulus, + const std::string &m_exponent) +{ + (void) m_modulus; + (void) m_exponent; + LogError("Not implemented."); + return UNKNOWN_ERROR; + // if (m_exponent.empty() || m_modulus.empty()) + // return WRONG_ARGUMENTS; + // + // CertificateLoaderRSA comparator(m_modulus,m_exponent); + // + // CertificateLoaderResult result = NO_ERROR; + // for(int i=0; storeId[i]; ++i){ + // result = loadCertificate(std::string(storeId[i]), &comparator); + // + // if(result == ERR_NO_MORE_CERTIFICATES) + // continue; + // + // return result; + // } + // + // return result; +} + +CertificateLoader::CertificateLoaderResult CertificateLoader::loadCertificate( + const std::string &storageName, + CertificateLoader::CertificateLoaderComparator *cmp) +{ + (void) storageName; + (void) cmp; + LogError("Not Implemented"); + return UNKNOWN_ERROR; + // long int result = OPERATION_SUCCESS; + // + // char storeId[CERTMGR_MAX_PLUGIN_ID_SIZE]; + // char type[CERTMGR_MAX_CERT_TYPE_SIZE]; + // certmgr_cert_id certId; + // certmgr_ctx context; + // certmgr_mem_buff certRetrieved; + // unsigned char buffer[CERTMGR_MAX_BUFFER_SIZE]; + // + // certmgr_cert_descriptor descriptor; + // + // certRetrieved.data = buffer; + // certRetrieved.firstFree = 0; + // certRetrieved.size = CERTMGR_MAX_BUFFER_SIZE; + // certId.storeId = storeId; + // certId.type = type; + // + // CERTMGR_INIT_CONTEXT((&context), (sizeof(context))) + // + // strncpy(context.storeId, storageName.c_str(), storageName.size()); + // + // for(certRetrieved.firstFree = 0; + // OPERATION_SUCCESS == (result = certmgr_retrieve_certificate_from_store(&context, &certRetrieved, &certId)); + // certRetrieved.firstFree = 0) + // { + // + // if(OPERATION_SUCCESS!=certmgr_extract_certificate_data(&certRetrieved, &descriptor)){ + // LogError("Extracting Certificate Data failed \n"); + // continue; + // } + // + // const unsigned char *ptr = certRetrieved.data; + // + // X509 *x509cert = d2i_X509(NULL, &ptr, certRetrieved.size); + // if(x509cert == NULL){ + // certmgr_release_certificate_data(&descriptor); + // LogError("Error extracting certificate (d2i_X509)."); + // return UNKNOWN_ERROR; + // } + // + // LogDebug("The subject of this certificate is " << descriptor.mandatory.subject); + // if(cmp->compare(x509cert)){ + // LogDebug("Found match. Coping bytes: " << certRetrieved.size); + // m_certificatePtr = CertificatePtr(new Certificate(certRetrieved)); + // certmgr_release_certificate_data(&descriptor); + // X509_free(x509cert); + // break; + // } + // + // LogDebug("Release"); + // X509_free(x509cert); + // certmgr_release_certificate_data(&descriptor); + // } + // + // if(ERR_NO_MORE_CERTIFICATES == result){ + // LogError("Certificates for given DN not found\n"); + // return CERTIFICATE_NOT_FOUND; + // } + // + // if(result!= OPERATION_SUCCESS){ + // LogError("Certificate Manager Error\n"); + // return UNKNOWN_ERROR; + // } + // + // LogDebug("Exit"); + // return NO_ERROR; +} + +// TODO +CertificateLoader::CertificateLoaderResult CertificateLoader:: + loadCertificateBasedOnSubjectName(const std::string &subjectName) +{ + (void) subjectName; + LogError("Not implemented."); + return UNKNOWN_ERROR; + // if(subjectName.empty()) + // { + // return WRONG_ARGUMENTS; + // } + // + // long int result = OPERATION_SUCCESS; + // + // char storeId[CERTMGR_MAX_PLUGIN_ID_SIZE]; + // char type[CERTMGR_MAX_CERT_TYPE_SIZE]; + // certmgr_cert_id certId; + // certmgr_ctx context; + // certmgr_mem_buff certRetrieved; + // unsigned char buffer[CERTMGR_MAX_BUFFER_SIZE]; + // + // certmgr_cert_descriptor descriptor; + // + // certRetrieved.data = buffer; + // certRetrieved.firstFree = 0; + // certRetrieved.size = CERTMGR_MAX_BUFFER_SIZE; + // certId.storeId = storeId; + // certId.type = type; + // + // CERTMGR_INIT_CONTEXT((&context), (sizeof(context))) + // + // for(certRetrieved.firstFree = 0; + // OPERATION_SUCCESS == (result = certmgr_retrieve_certificate_from_store(&context, &certRetrieved, &certId)); + // certRetrieved.firstFree = 0) + // { + // + // if(OPERATION_SUCCESS!=certmgr_extract_certificate_data(&certRetrieved, &descriptor)){ + // LogError("Extracting Certificate Data failed \n"); + // continue; + // } + // + // if(!strcmp(subjectName.c_str(), descriptor.mandatory.subject)){ + // LogDebug("The subject of this certificate is " << descriptor.mandatory.subject); + // m_certificatePtr = CertificatePtr(new Certificate(certRetrieved)); + // certmgr_release_certificate_data(&descriptor); + // break; + // } + // LogDebug("Release"); + // certmgr_release_certificate_data(&descriptor); + // } + // + // if(ERR_NO_MORE_CERTIFICATES == result) { + // LogError("Certificates for given DN not found\n"); + // return CERTIFICATE_NOT_FOUND; + // } + // if(result!= OPERATION_SUCCESS){ + // LogError("Certificate Manager Error\n"); + // return UNKNOWN_ERROR; + // } + // LogDebug("Exit"); + // return NO_ERROR; +} + +// KW CertificateLoader::CertificateLoaderResult CertificateLoader::loadCertificateBasedOnIssuerName(const std::string &issuerName, const std::string &serialNumber) +// KW { +// KW if(issuerName.empty() || serialNumber.empty()) +// KW { +// KW return WRONG_ARGUMENTS; +// KW } +// KW +// KW if(m_cmBuff.data){ +// KW delete[] m_cmBuff.data; +// KW memset(&m_cmBuff, 0, sizeof(certmgr_mem_buff)); +// KW } +// KW +// KW LogDebug("IssuerName: " << issuerName << " serialNumber: " << serialNumber); +// KW +// KW //used to check status of retrieved certificate +// KW long int result = OPERATION_SUCCESS; +// KW char storeId[CERTMGR_MAX_PLUGIN_ID_SIZE]; +// KW char type[CERTMGR_MAX_CERT_TYPE_SIZE]; +// KW certmgr_cert_id certId; +// KW certmgr_ctx context; +// KW certmgr_mem_buff certRetrieved; +// KW unsigned char buffer[CERTMGR_MAX_BUFFER_SIZE]; +// KW +// KW certmgr_cert_descriptor descriptor; +// KW +// KW certRetrieved.data = buffer; +// KW certRetrieved.firstFree = 0; +// KW certRetrieved.size = CERTMGR_MAX_BUFFER_SIZE; +// KW certId.storeId = storeId; +// KW certId.type = type; +// KW +// KW CERTMGR_INIT_CONTEXT((&context), (sizeof(context))) +// KW +// KW for(certRetrieved.firstFree = 0; +// KW OPERATION_SUCCESS == (result = certmgr_retrieve_certificate_from_store(&context, &certRetrieved, &certId)); +// KW certRetrieved.firstFree = 0) +// KW { +// KW +// KW LogDebug("Extracting certificate from CertMgr"); +// KW +// KW if( OPERATION_SUCCESS != certmgr_extract_certificate_data(&certRetrieved, &descriptor) ){ +// KW LogError("Extracting Certificate Data failed \n"); +// KW continue; +// KW } +// KW +// KW LogDebug("Issuer: " << descriptor.mandatory.issuer); +// KW +// KW const unsigned char *ptr = certRetrieved.data; +// KW char *tmp; +// KW +// KW X509 *x509cert = d2i_X509(NULL, &ptr, certRetrieved.size); +// KW std::string serialNO = std::string(tmp = i2s_ASN1_INTEGER(NULL, X509_get_serialNumber(x509cert))); +// KW OPENSSL_free(tmp); +// KW X509_free(x509cert); +// KW +// KW LogInfo("Certificate number found: " << serialNO); +// KW LogInfo("Certificate number looking for: " << serialNumber); +// KW +// KW if(!strcmp(issuerName.c_str(), descriptor.mandatory.issuer) +// KW && serialNumber == serialNO) +// KW { +// KW LogError("The issuer of this certificate is " << descriptor.mandatory.issuer); +// KW +// KW m_cmBuff.data = new unsigned char[certRetrieved.size]; +// KW m_cmBuff.firstFree = m_cmBuff.size = certRetrieved.size; +// KW memcpy(m_cmBuff.data, certRetrieved.data, certRetrieved.size); +// KW certmgr_release_certificate_data(&descriptor); +// KW break; +// KW } +// KW certmgr_release_certificate_data(&descriptor); +// KW } +// KW +// KW if(ERR_NO_MORE_CERTIFICATES == result) { +// KW LogError("Certificates not found"); +// KW return CERTIFICATE_NOT_FOUND; +// KW } +// KW if(result != OPERATION_SUCCESS){ +// KW LogError("Certificate Manager Error"); +// KW return UNKNOWN_ERROR; +// KW } +// KW return NO_ERROR; +// KW } + +CertificateLoader::CertificateLoaderResult CertificateLoader:: + loadCertificateWithECKEY(const std::string &curveName, + const std::string &publicKey) +{ + (void) curveName; + (void) publicKey; + LogError("Not implemented."); + return UNKNOWN_ERROR; + // if(curveName != OID_CURVE_SECP256R1){ + // LogError("Found field id: " << curveName << " Expected: " << OID_CURVE_SECP256R1); + // return UNSUPPORTED_CERTIFICATE_FIELD; + // } + // + // CertificateLoaderECDSA comparator(publicKey); + // + // CertificateLoaderResult result = NO_ERROR; + // for(int i=0; storeId[i]; ++i){ + // result = loadCertificate(std::string(storeId[i]), &comparator); + // + // if(result == ERR_NO_MORE_CERTIFICATES) + // continue; + // + // return result; + // } + // + // return result; +} + +CertificateLoader::CertificateLoaderResult CertificateLoader:: + loadCertificateFromRawData(const std::string &rawData) +{ + Try { + m_certificatePtr = + CertificatePtr(new Certificate(rawData, Certificate::FORM_BASE64)); + } Catch(Certificate::Exception::Base) { + LogWarning("Error reading certificate by openssl."); + return UNKNOWN_ERROR; + } + + // Check the key length if sig algorithm is RSA + EVP_PKEY *pKey = X509_get_pubkey(m_certificatePtr->getX509()); + + if (pKey->type == EVP_PKEY_RSA) { + RSA* pRSA = pKey->pkey.rsa; + + if (pRSA) { + int keyLength = RSA_size(pRSA); + + // key Length (modulus) is in bytes + keyLength <<= 3; + LogDebug("RSA key length: " << keyLength << " bits"); + + if (keyLength < MIN_RSA_KEY_LENGTH) { + LogError( + "RSA key too short!" << "Has only " << keyLength << " bits"); + return CERTIFICATE_SECURITY_ERROR; + } + } + } + + return NO_ERROR; +} + +// DEPRACETED FUNCTION +//CertificateLoader::CertificateLoaderResult CertificateLoader::loadCertificateFromRawData(const std::string &rawData) +//{ +// certmgr_mem_buff cmBuff = {0,0,0}; +// +// long int size; +// cmBuff.data = certmgr_util_base64_decode(const_cast(static_cast(rawData.c_str())), rawData.size(), &size); +// +// cmBuff.firstFree = cmBuff.size = size; +// +// certmgr_cert_descriptor descriptor; +// +// long int result = certmgr_extract_certificate_data(&cmBuff, &descriptor); +// +// if (result != OPERATION_SUCCESS) +// { +// LogError("Unable to load certificate"); +// return UNKNOWN_ERROR; +// } +// +// certmgr_release_certificate_data(&descriptor); +// +// m_certificatePtr = CertificatePtr(new Certificate(cmBuff)); +// +// // we have to use temp pointer cause d2i_x509 modifies its input +// const unsigned char* tmpPtr = cmBuff.data; +// X509* pCertificate = d2i_X509(NULL, &tmpPtr, cmBuff.size); +// +// if (pCertificate) +// { +// SSLSmartContainer pX509(pCertificate); +// +// // Check the key length if sig algorithm is RSA +// EVP_PKEY *pKey = X509_get_pubkey(pX509); +// +// if (pKey->type == EVP_PKEY_RSA) +// { +// RSA* pRSA = pKey->pkey.rsa; +// +// if (pRSA) +// { +// int keyLength = RSA_size(pRSA); +// +// // key Length (modulus) is in bytes +// keyLength <<= 3; +// LogDebug("RSA key length: " << keyLength << " bits"); +// +// if (keyLength < MIN_RSA_KEY_LENGTH) +// { +// LogError("RSA key too short!" << "Has only " << keyLength << " bits"); +// return CERTIFICATE_SECURITY_ERROR; +// } +// } +// } +// } +// +// return NO_ERROR; +//} + +CertificateLoader::CertificateLoaderResult CertificateLoader:: + loadCertificateBasedOnDSAComponents(const std::string& strP, + const std::string& strQ, + const std::string& strG, + const std::string& strY, + const std::string& strJ, + const std::string& strSeed, + const std::string& strPGenCounter) +{ + (void) strP; + (void) strQ; + (void) strG; + (void) strY; + (void) strJ; + (void) strSeed; + (void) strPGenCounter; + LogError("Not implemented."); + return UNKNOWN_ERROR; + // (void)strY; + // (void)strJ; + // (void)strSeed; + // (void)strPGenCounter; + // + // long int result = UNKNOWN_ERROR; + // + // char storeId[CERTMGR_MAX_PLUGIN_ID_SIZE]; + // char type[CERTMGR_MAX_CERT_TYPE_SIZE]; + // certmgr_cert_id certId; + // certmgr_ctx context; + // certmgr_mem_buff certRetrieved; + // + // unsigned char buffer[CERTMGR_MAX_BUFFER_SIZE]; + // + // certmgr_cert_descriptor descriptor; + // + // certRetrieved.data = buffer; + // certRetrieved.firstFree = 0; + // certRetrieved.size = CERTMGR_MAX_BUFFER_SIZE; + // certId.storeId = storeId; + // certId.type = type; + // + // CERTMGR_INIT_CONTEXT((&context), (sizeof(context))) + // std::string strStoreType("Operator"); + // strncpy(context.storeId, strStoreType.c_str(), strStoreType.length()); + // + // for (certRetrieved.firstFree = 0; + // OPERATION_SUCCESS == (result = certmgr_retrieve_certificate_from_store(&context, &certRetrieved, &certId)); + // certRetrieved.firstFree = 0) + // { + // + // if (OPERATION_SUCCESS != certmgr_extract_certificate_data(&certRetrieved, &descriptor)) + // { + // LogDebug("unable to retrieve cert from storage"); + // continue; + // } + // + // X509* pCertificate = d2i_X509(NULL, (const unsigned char**) &(certRetrieved.data), certRetrieved.size); + // + // if (pCertificate) + // { + // EVP_PKEY *pKey = X509_get_pubkey(pCertificate); + // + // if (pKey->type == EVP_PKEY_DSA) + // { + // DSA* pDSA = pKey->pkey.dsa; + // + // if (pDSA) + // { + // BIGNUM *pDSApBigNum = NULL, *pDSAqBigNum = NULL, *pDSAgBigNum = NULL; + // + // convertBase64NodeToBigNum(strP, &pDSApBigNum); + // convertBase64NodeToBigNum(strQ, &pDSAqBigNum); + // convertBase64NodeToBigNum(strG, &pDSAgBigNum); + // + // if (pDSApBigNum && pDSAqBigNum && pDSAgBigNum && + // BN_cmp(pDSApBigNum, pDSA->p) == 0 && + // BN_cmp(pDSAqBigNum, pDSA->q) == 0 && + // BN_cmp(pDSAgBigNum, pDSA->g) == 0) + // { + // LogInfo("DSA Certificate found"); + // /* TODO load this certificate to m_cmBuff value */ + // LogError("Not implemented!"); + // + // EVP_PKEY_free(pKey); + // X509_free(pCertificate); + // + // BN_free(pDSApBigNum); + // BN_free(pDSAqBigNum); + // BN_free(pDSAgBigNum); + // + // certmgr_release_certificate_data(&descriptor); + // return NO_ERROR; + // } + // + // if (pDSApBigNum) + // { + // BN_free(pDSApBigNum); + // } + // if (pDSAqBigNum) + // { + // BN_free(pDSAqBigNum); + // } + // if (pDSAgBigNum) + // { + // BN_free(pDSAgBigNum); + // } + // + // } + // EVP_PKEY_free(pKey); + // } + // X509_free(pCertificate); + // } + // else + // LogError("Unable to load certificate"); + // + // certmgr_release_certificate_data(&descriptor); + // } + // + // LogError("No DSA certificate with given parameters"); + // + // return CERTIFICATE_NOT_FOUND; +} + +bool CertificateLoader::convertBase64NodeToBigNum(const std::string& strNode, + BIGNUM** ppBigNum) +{ + (void) strNode; + (void) ppBigNum; + LogError("Not implemented."); + return false; + // if (!ppBigNum || *ppBigNum != NULL) + // { + // LogError("Ptr variable not initialized properly!"); + // return false; + // } + // + // // decode base64 to binary + // long int binBuffLength = 0; + // unsigned char* binBuff = NULL; + // + // binBuff = certmgr_util_base64_decode(const_cast (strNode.c_str()), strNode.length(), &binBuffLength); + // + // if (!binBuff) + // { + // LogError("base64 decode failed"); + // return false; + // } + // + // // convert binary to bignum + // *ppBigNum = BN_bin2bn(binBuff, binBuffLength, *ppBigNum); + // + // free(binBuff); + // + // if (!(*ppBigNum)) + // { + // LogError("Conversion from node to bignum failed"); + // return false; + // } + // + // return true; +} + +// KW bool CertificateLoader::convertBigNumToBase64Node(const BIGNUM* pBigNum, std::string& strNode) +// KW { +// KW if (!pBigNum) +// KW { +// KW LogError("null ptr"); +// KW return false; +// KW } +// KW +// KW int nNumLength = BN_num_bytes(pBigNum); +// KW unsigned char* buffer = new unsigned char[nNumLength + 1]; +// KW +// KW // convert bignum to binary format +// KW if (BN_bn2bin(pBigNum, buffer) < 0) +// KW { +// KW LogError("Conversion from bignum to binary failed"); +// KW delete []buffer; +// KW return false; +// KW } +// KW +// KW char* pBase64Node = NULL; +// KW unsigned long int buffLen = 0; +// KW certmgr_util_base64_encode(buffer, (unsigned long int) nNumLength, &pBase64Node, &buffLen); +// KW +// KW strNode.assign(pBase64Node, buffLen); +// KW +// KW delete []buffer; +// KW return true; +// KW } +} // namespace ValidationCore + diff --git a/vcore/src/vcore/CertificateLoader.h b/vcore/src/vcore/CertificateLoader.h new file mode 100644 index 0000000..64c38ac --- /dev/null +++ b/vcore/src/vcore/CertificateLoader.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011 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. + */ +#ifndef _CERTIFICATELOADER_H_ +#define _CERTIFICATELOADER_H_ + +#include +#include + +#include +#include + +#include + +#include "Certificate.h" + +namespace ValidationCore { +class CertificateLoader : public DPL::Noncopyable +{ + public: + class CertificateLoaderComparator + { + public: + virtual bool compare(X509 *x509cert) = 0; + virtual ~CertificateLoaderComparator() + { + } + }; + + enum CertificateLoaderResult + { + NO_ERROR, + CERTIFICATE_NOT_FOUND, + UNSUPPORTED_CERTIFICATE_FIELD, + WRONG_ARGUMENTS, + CERTIFICATE_SECURITY_ERROR, //!< there are some issues with certificate security (i.e. key too short) + UNKNOWN_ERROR + }; + + CertificateLoader() + { + } + + virtual ~CertificateLoader() + { + } + + CertificateLoaderResult loadCertificate(const std::string& storage, + CertificateLoaderComparator *cmp); + + CertificateLoaderResult loadCertificateBasedOnSubjectName( + const std::string &subjectName); + CertificateLoaderResult loadCertificateBasedOnExponentAndModulus( + const std::string &m_modulus, + const std::string &m_exponent); + // KW CertificateLoaderResult loadCertificateBasedOnIssuerName(const std::string &isserName, + // KW const std::string &serialNumber); + + CertificateLoaderResult loadCertificateFromRawData( + const std::string &rawData); + + CertificateLoaderResult loadCertificateBasedOnDSAComponents( + const std::string& strP, + const std::string& strQ, + const std::string& strG, + const std::string& strY, + const std::string& strJ, + const std::string& strSeed, + const std::string& strPGenCounter); + + CertificateLoaderResult loadCertificateWithECKEY( + const std::string &curveName, + const std::string &publicKey); + + /** + * converts base64 encoded node to SSL bignum + * allocates mem on *ppBigNum, don't forget to free it later with BN_free! + * returns conversion status + */ + static bool convertBase64NodeToBigNum(const std::string& strNode, + BIGNUM** ppBigNum); + + /* + * encodes SSL bignum into base64 octstring + * returns conversion status + */ + // KW static bool convertBigNumToBase64Node(const BIGNUM* pBigNum, std::string& strNode); + + CertificatePtr getCertificatePtr() const + { + return m_certificatePtr; + } + private: + CertificatePtr m_certificatePtr; +}; +} // namespace ValidationCore + +#endif // _CERTIFICATELOADER_H_ diff --git a/vcore/src/vcore/CertificateStorage.h b/vcore/src/vcore/CertificateStorage.h new file mode 100644 index 0000000..7fbcb6b --- /dev/null +++ b/vcore/src/vcore/CertificateStorage.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011 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. + */ +#ifndef VCORE_SRC_VCORE_CERTIFICATESTORAGE_H +#define VCORE_SRC_VCORE_CERTIFICATESTORAGE_H + +#include +#include + +namespace ValidationCore { +typedef std::list < X509* > X509CertificatesList; +} + +#endif // VCORE_SRC_VCORE_CERTIFICATESTORAGE_H diff --git a/vcore/src/vcore/CertificateVerifier.cpp b/vcore/src/vcore/CertificateVerifier.cpp new file mode 100644 index 0000000..f05662a --- /dev/null +++ b/vcore/src/vcore/CertificateVerifier.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Bartlomiej Grzelewski (b.grzelewski@gmail.com) + * @version 0.1 + * @file CertificateVerifier.cpp + * @brief This class integrates OCSP and CRL. + */ +#include "CertificateVerifier.h" + +#include +#include +#include + +namespace ValidationCore { + +CertificateVerifier::CertificateVerifier(bool enableOcsp, bool enableCrl) +: m_enableOcsp(enableOcsp) +, m_enableCrl(enableCrl) +{} + +VerificationStatus CertificateVerifier::check( + CertificateCollection &certCollection) const +{ + LogDebug("== Certificate collection validation start =="); + Assert(certCollection.isChain() && "Collection must form chain."); + + VerificationStatus statusOcsp; + VerificationStatus statusCrl; + + if (m_enableOcsp) { + statusOcsp = obtainOcspStatus(certCollection); + } else { + statusOcsp = VERIFICATION_STATUS_GOOD; + } + + if (m_enableCrl) { + statusCrl = obtainCrlStatus(certCollection); + } else { + statusCrl = VERIFICATION_STATUS_GOOD; + } + LogDebug("== Certificate collection validation end =="); + return getStatus(statusOcsp, statusCrl); +} + +VerificationStatus CertificateVerifier::obtainOcspStatus( + const CertificateCollection &chain) const +{ + LogDebug("== Obtain ocsp status =="); + CachedOCSP ocsp; + return ocsp.check(chain); +} + +VerificationStatus CertificateVerifier::obtainCrlStatus( + const CertificateCollection &chain) const +{ + LogDebug("== Obtain crl status =="); + CachedCRL crl; + return crl.check(chain); +} + +VerificationStatus CertificateVerifier::getStatus( + VerificationStatus ocsp, + VerificationStatus crl) const +{ + if (ocsp == VERIFICATION_STATUS_REVOKED || + crl == VERIFICATION_STATUS_REVOKED) + { + LogDebug("Return status: REVOKED"); + return VERIFICATION_STATUS_REVOKED; + } + + if (ocsp == VERIFICATION_STATUS_GOOD) { + LogDebug("Return status: GOOD"); + return VERIFICATION_STATUS_GOOD; + } + + if (ocsp == VERIFICATION_STATUS_UNKNOWN) { + LogDebug("Return status: UNKNOWN"); + return VERIFICATION_STATUS_UNKNOWN; + } + + if (ocsp == VERIFICATION_STATUS_NOT_SUPPORT) { + LogDebug("Return status: NOT_SUPPORT"); + return VERIFICATION_STATUS_GOOD; + } + + LogDebug("Return status: ERROR"); + return VERIFICATION_STATUS_ERROR; +} + +VerificationStatus CertificateVerifier::checkEndEntity( + CertificateCollectionList &collectionList) const +{ + VerificationStatusSet statusOcsp; + VerificationStatusSet statusCrl; + + if (m_enableOcsp) { + CachedOCSP ocsp; + FOREACH(it, collectionList){ + statusOcsp.add(ocsp.checkEndEntity(*it)); + } + } else { + statusOcsp.add(VERIFICATION_STATUS_GOOD); + } + + if (m_enableCrl) { + CachedCRL crl; + FOREACH(it, collectionList){ + statusCrl.add(crl.checkEndEntity(*it)); + } + } else { + statusCrl.add(VERIFICATION_STATUS_GOOD); + } + LogDebug("== Certificate collection validateion end =="); + return getStatus(statusOcsp.convertToStatus(), statusCrl.convertToStatus()); +} + +} // namespace ValidationCore diff --git a/vcore/src/vcore/CertificateVerifier.h b/vcore/src/vcore/CertificateVerifier.h new file mode 100644 index 0000000..ea77812 --- /dev/null +++ b/vcore/src/vcore/CertificateVerifier.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Bartlomiej Grzelewski (b.grzelewski@gmail.com) + * @version 0.1 + * @file CertificateVerifier.h + * @brief This class integrates OCSP and CRL into one module. + */ +#ifndef _SRC_VALIDATION_CORE_CERTIFICATE_VERIFIER_H_ +#define _SRC_VALIDATION_CORE_CERTIFICATE_VERIFIER_H_ + +#include "Certificate.h" +#include "CertificateCollection.h" +#include "CachedCRL.h" +#include "CachedOCSP.h" +#include "VerificationStatus.h" + +namespace ValidationCore { + +class CertificateVerifier { + public: + explicit CertificateVerifier(bool enableOcsp, bool enableCrl); + ~CertificateVerifier(){} + + /* + * Run OCSP and CRL for all certificates in collection. + * Collection must represent chain. + * + * Evaluate status. This function converts ocsp status set + * into one status - the most restricted. This one ocsp status + * and status from crl is evaluated to end result. + * + * Algorithm to evaluate result is represented in table: + * + * +--------------+-------+-------+-------+------------+---------+ + * | OCSP |Good |Revoked|Unknown|Undetermined|Not | + * | | | | | |supported| + * | CRL | | | | | | + * +--------------+-------+-------+-------+------------+---------+ + * | GOOD |GOOD |Revoked|Unknown|Undetermined|Good | + * +--------------+-------+-------+-------+------------+---------+ + * | REVOKED |Revoked|Revoked|Revoked|Revoked |Revoked | + * +--------------+-------+-------+-------+------------+---------+ + * | UNDETERMINED |Good |Revoked|Unknown|Undetermined|Good | + * +--------------+-------+-------+-------+------------+---------+ + * | Not supported|Good |Revoked|Unknown|Undetermined|Good | + * +--------------+-------+-------+-------+------------+---------+ + * + * As Undetermind function returns VERIFICATION_STATUS_ERROR. + */ + + VerificationStatus check(CertificateCollection &certCollection) const; + + VerificationStatus checkEndEntity( + CertificateCollectionList &certCollectionList) const; + + private: + VerificationStatus obtainOcspStatus( + const CertificateCollection &chain) const; + VerificationStatus obtainCrlStatus( + const CertificateCollection &chain) const; + VerificationStatus getStatus(VerificationStatus ocsp, + VerificationStatus crl) const; + + bool m_enableOcsp; + bool m_enableCrl; +}; + +} // namespace ValidationCore + +#endif // _SRC_VALIDATION_CORE_CERTIFICATE_VERIFIER_H_ + diff --git a/vcore/src/vcore/Config.cpp b/vcore/src/vcore/Config.cpp new file mode 100644 index 0000000..7dfaedf --- /dev/null +++ b/vcore/src/vcore/Config.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2011 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. + */ + +#include "Config.h" + +#include +IMPLEMENT_SINGLETON(ValidationCore::Config) diff --git a/vcore/src/vcore/Config.h b/vcore/src/vcore/Config.h new file mode 100644 index 0000000..a810414 --- /dev/null +++ b/vcore/src/vcore/Config.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 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. + */ + +#ifndef _SRC_VALIDATION_CORE_VALIDATION_CORE_CONFIG_H_ +#define _SRC_VALIDATION_CORE_VALIDATION_CORE_CONFIG_H_ + +#include + +#include + +namespace ValidationCore { +class Config { +public: + /* + * Set path to config file with certificate description. + */ + bool setXMLConfigPath(const std::string& path) { + if (!m_certificateXMLConfigPath.empty()) { + return false; + } + m_certificateXMLConfigPath = path; + return true; + } + + /* + * Set path to schema of config file. + */ + bool setXMLSchemaPath(const std::string& path) { + if (!m_certificateXMLSchemaPath.empty()) { + return false; + } + m_certificateXMLSchemaPath = path; + return true; + } + + /* + * Get path to config file with certificate description. + */ + std::string getXMLConfigPath() { + return m_certificateXMLConfigPath; + } + + /* + * Get path to schema of config file. + */ + std::string getXMLSchemaPath() { + return m_certificateXMLSchemaPath; + } + +private: + std::string m_certificateXMLConfigPath; + std::string m_certificateXMLSchemaPath; +}; + +typedef DPL::Singleton ConfigSingleton; + +} // namespace ValidationCore + +#endif // _SRC_VALIDATION_CORE_VALIDATION_CORE_CONFIG_H_ + diff --git a/vcore/src/vcore/Database.cpp b/vcore/src/vcore/Database.cpp new file mode 100644 index 0000000..d68b280 --- /dev/null +++ b/vcore/src/vcore/Database.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 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 webruntime_database.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file contains the definition of webruntime database + */ +#include "Database.h" + +DPL::Mutex g_vcoreDbQueriesMutex; diff --git a/vcore/src/vcore/Database.h b/vcore/src/vcore/Database.h new file mode 100644 index 0000000..ca6efa2 --- /dev/null +++ b/vcore/src/vcore/Database.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 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 webruntime_database.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of webruntime database + */ +#ifndef VCORE_SRC_VCORE_DATABASE_H +#define VCORE_SRC_VCORE_DATABASE_H + +#include +#include +#include +#include + +extern DPL::Mutex g_vcoreDbQueriesMutex; + +#define VCORE_DB_INTERNAL(tlsCommand, InternalType, interface) \ + static DPL::ThreadLocalVariable *tlsCommand ## Ptr = NULL; \ + { \ + DPL::Mutex::ScopedLock lock(&g_vcoreDbQueriesMutex); \ + if (!tlsCommand ## Ptr) { \ + static DPL::ThreadLocalVariable tmp; \ + tlsCommand ## Ptr = &tmp; \ + } \ + } \ + DPL::ThreadLocalVariable &tlsCommand = *tlsCommand ## Ptr; \ + if (tlsCommand.IsNull()) { tlsCommand = InternalType(interface); } + +#define VCORE_DB_SELECT(name, type, interface) \ + VCORE_DB_INTERNAL(name, type::Select, interface) + +#define VCORE_DB_INSERT(name, type, interface) \ + VCORE_DB_INTERNAL(name, type::Insert, interface) + +#define VCORE_DB_UPDATE(name, type, interface) \ + VCORE_DB_INTERNAL(name, type::Update, interface) + +#define VCORE_DB_DELETE(name, type, interface) \ + VCORE_DB_INTERNAL(name, type::Delete, interface) + +#endif // define VCORE_SRC_VCORE_DATABASE_H diff --git a/vcore/src/vcore/DeveloperModeValidator.cpp b/vcore/src/vcore/DeveloperModeValidator.cpp new file mode 100644 index 0000000..fa9e7d2 --- /dev/null +++ b/vcore/src/vcore/DeveloperModeValidator.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011 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 DeveloperModeValidator.cpp + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief DeveloperModeValidatorValidator - implementing WAC 2.0 spec, including TargetRestriction + */ + +#include "DeveloperModeValidator.h" +#include +#include +#include +#include + +namespace ValidationCore { + +DeveloperModeValidator::DeveloperModeValidator(bool complianceMode, + const std::string& fakeIMEI, + const std::string& fakeMEID) : + m_complianceModeEnabled(complianceMode), + m_developerModeEnabled(true), + m_fakeIMEI(fakeIMEI), + m_fakeMEID(fakeMEID) +{ +} + +DeveloperModeValidator::DeveloperModeValidator(bool complianceMode, + bool developerMode, + const std::string& fakeIMEI, + const std::string& fakeMEID, + const std::string& realMEID) : + m_complianceModeEnabled(complianceMode), + m_developerModeEnabled(developerMode), + m_fakeIMEI(fakeIMEI), + m_fakeMEID(fakeMEID), + m_realMEID(realMEID) +{ +} + +void DeveloperModeValidator::check(const SignatureData &data) +{ + LogDebug("entered"); + const SignatureData::IMEIList& IMEIList = data.getIMEIList(); + const SignatureData::MEIDList& MEIDList = data.getMEIDList(); + + if (IMEIList.empty() && MEIDList.empty()) { + LogDebug("No TargetRestriction in signature."); + return; + } + + if (!m_developerModeEnabled) { + Throw(Exception::NoTargetRestrictionSatisfied); + } + + if (!IMEIList.empty()) { + std::string phoneIMEIString = m_fakeIMEI; + if (!m_complianceModeEnabled) { + LogDebug("Compilance Mode is not enabled"); + DPL::ScopedFree phoneIMEI( + vconf_get_str(VCONFKEY_TELEPHONY_IMEI)); + if (!phoneIMEI.Get()) { + ThrowMsg(Exception::NoTargetRestrictionSatisfied, + "Unable to get phone IMEI from vconf."); + } + phoneIMEIString = phoneIMEI.Get(); + } + + LogDebug("Phone IMEI: " << phoneIMEIString); + if (IMEIList.end() == + std::find(IMEIList.begin(), IMEIList.end(), phoneIMEIString)) + { + Throw(Exception::NoTargetRestrictionSatisfied); + } + } + + if (!MEIDList.empty()) { + std::string phoneMEIDString = m_fakeMEID; + if (!m_complianceModeEnabled) + { + if (m_realMEID.empty()) + { + ThrowMsg(Exception::NoTargetRestrictionSatisfied, + "Unable to get phone MEID from Tapi service."); + } + phoneMEIDString = m_realMEID; + } + + LogDebug("Phone MEID: " << phoneMEIDString); + if (MEIDList.end() == + std::find(MEIDList.begin(), MEIDList.end(), phoneMEIDString)) + { + Throw(Exception::NoTargetRestrictionSatisfied); + } + } + LogDebug("exit: ok"); +} + +} //ValidationCore diff --git a/vcore/src/vcore/DeveloperModeValidator.h b/vcore/src/vcore/DeveloperModeValidator.h new file mode 100644 index 0000000..9a2c87a --- /dev/null +++ b/vcore/src/vcore/DeveloperModeValidator.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011 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 DeveloperModeValidator.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief DeveloperModeValidatorValidator - implementing WAC 2.0 spec, including TargetRestriction + */ + +#ifndef \ + WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_DEVELOPER_MODE_VALIDATOR_H +#define \ + WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_DEVELOPER_MODE_VALIDATOR_H + +#include +#include +#include "SignatureData.h" + +namespace ValidationCore { + +class DeveloperModeValidator +{ + public: + explicit DeveloperModeValidator( + bool complianceMode = false, + const std::string &fakeIMEI = "", + const std::string &fakeMEID = "") __attribute__((deprecated)); + + explicit DeveloperModeValidator(bool complianceMode = false, + bool developerMode = false, + const std::string &fakeIMEI = "", + const std::string &fakeMEID = "", + const std::string &realMEID = ""); + + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, UnableToLoadTestCertificate) + DECLARE_EXCEPTION_TYPE(Base, NoTargetRestrictionSatisfied) + }; + + void check(const SignatureData &data); + private: + bool m_complianceModeEnabled; + bool m_developerModeEnabled; + std::string m_fakeIMEI; + std::string m_fakeMEID; + std::string m_realMEID; +}; + +} +#endif /* WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_DEVELOPER_MODE_VALIDATOR_H */ + diff --git a/vcore/src/vcore/IAbstractResponseCache.h b/vcore/src/vcore/IAbstractResponseCache.h new file mode 100644 index 0000000..38a6fa8 --- /dev/null +++ b/vcore/src/vcore/IAbstractResponseCache.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 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 AbstractResponseCache.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 0.1 + * @brief Common interface for OCSP/CRL caches + */ + +#ifndef _SRC_VALIDATION_CORE_IABSTRACT_RESPONSE_CACHE_H_ +#define _SRC_VALIDATION_CORE_IABSTRACT_RESPONSE_CACHE_H_ + +#include "Certificate.h" +#include "CertificateCollection.h" +#include "VerificationStatus.h" + +namespace ValidationCore { + +class IAbstractResponseCache { + public: + virtual VerificationStatus check(const CertificateCollection &certs) = 0; + virtual VerificationStatus checkEndEntity(CertificateCollection &certs) = 0; + virtual void updateCache() = 0; + + virtual ~IAbstractResponseCache() + { + } +}; + +} // namespace ValidationCore + +#endif /* _SRC_VALIDATION_CORE_IABSTRACT_RESPONSE_CACHE_H_ */ diff --git a/vcore/src/vcore/OCSP.cpp b/vcore/src/vcore/OCSP.cpp new file mode 100644 index 0000000..4c84d2b --- /dev/null +++ b/vcore/src/vcore/OCSP.cpp @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Tomasz Morawski(t.morawski@samsung.com) + * @author Michal Ciepielski(m.ciepielski@samsung.com) + * @author Piotr Marcinkiewicz(p.marcinkiew@samsung.com) + * @version 0.4 + * @file OCPS.cpp + * @brief Routines for certificate validation over OCSP + */ + +#include "OCSP.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "Certificate.h" +#include "SoupMessageSendSync.h" + +extern "C" { +// This function is needed to fix "Invalid conversion from void* +// to unsigned char*" C++ compiler error during calling +// i2d_OCSP_REQUEST_bio macro + extern bool convertToBuffer(OCSP_REQUEST* req, + char** buf, + int* size); +} + +namespace { +const int ConnectionTimeoutInSeconds = 6; +const int ConnectionRetryCount = 5; + +//! Maximum leeway in validity period in seconds: default 1 day +//! (@see checkRevocationStatus function code) + +//! Maximum validity time for revocation status (1 day) +const int MaxValidatyPeriodInSeconds = 24 * 60 * 60; + +//! Max age (@see checkRevocationStatus function code) +const int MaxAge = -1; +} + +namespace ValidationCore { + +const char* OCSP::DEFAULT_RESPONDER_URI_ENV = "OCSP_DEFAULT_RESPONDER_URI"; + +OCSP::DigestAlgorithmMap createDigestAlgMap() +{ + OCSP::DigestAlgorithmMap mDigestAlg = OCSP::DigestAlgorithmMap(); + + mDigestAlg.insert(std::make_pair(OCSP::SHA1, EVP_sha1())); + mDigestAlg.insert(std::make_pair(OCSP::SHA224, EVP_sha224())); + mDigestAlg.insert(std::make_pair(OCSP::SHA256, EVP_sha256())); + mDigestAlg.insert(std::make_pair(OCSP::SHA384, EVP_sha384())); + mDigestAlg.insert(std::make_pair(OCSP::SHA512, EVP_sha512())); + + return mDigestAlg; +} + +OCSP::DigestAlgorithmMap OCSP::m_sDigestAlgMap = createDigestAlgMap(); + +OCSP::OCSP() : + /* Upgrade of openssl is required to support sha256 */ + // m_pCertIdDigestAlg(EVP_sha256()), + // m_pRequestDigestAlg(EVP_sha256()), + m_pCertIdDigestAlg(EVP_sha1()), + m_pRequestDigestAlg(EVP_sha1()), + m_bUseNonce(false), + m_bUseDefResponder(false), + m_bSignRequest(false), + m_pSignKey(0) +{ +} + +SoupWrapper::SoupMessageSendBase::RequestStatus OCSP::sendOcspRequest( + OCSP_REQUEST* argRequest, + const DPL::OptionalString& argUri) +{ + using namespace SoupWrapper; + // convert OCSP_REQUEST to memory buffer + std::string url = DPL::ToUTF8String(*argUri); + char* requestBuffer; + int requestSizeInt; + if (!convertToBuffer(argRequest, &requestBuffer, &requestSizeInt)) { + ThrowMsg(OCSP::Exception::VerificationError, + "OCSP: failed to convert OCSP_REQUEST to mem buffer"); + } + + Assert(requestSizeInt >= 0); + + SoupMessageSendBase::MessageBuffer buffer; + buffer.resize(requestSizeInt); + memcpy(&buffer[0], requestBuffer, requestSizeInt); + free(requestBuffer); + + char *cport = 0,*chost = 0,*cpath = 0; + int use_ssl = 0; + + if (!OCSP_parse_url(const_cast(url.c_str()), + &chost, + &cport, + &cpath, + &use_ssl)) + { + LogWarning("Error in OCSP_parse_url"); + return SoupMessageSendBase::REQUEST_STATUS_CONNECTION_ERROR; + } + + std::string host = chost; + + if (cport) { + host += ":"; + host += cport; + } + + free(cport); + free(chost); + free(cpath); + + m_soupMessage.setHost(url); + m_soupMessage.setHeader("Host", host); + m_soupMessage.setRequest(std::string("application/ocsp-request"), + buffer); + + return m_soupMessage.sendSync(); +} + +ValidationCore::VerificationStatusSet OCSP::validateCertificateList( + const CertificateList &certs) +{ + VerificationStatusSet statusSet; + + if (certs.size() < 2) { + // no certificates to verify, just return a error + LogWarning("No validation will be proceed. OCSP require at" + " least 2 certificates in chain. Found only " << + certs.size()); + statusSet.add(VERIFICATION_STATUS_ERROR); + return statusSet; + } + + CertificateList::const_iterator iter = certs.begin(); + CertificateList::const_iterator parent = iter; + + time_t minValidity = 0; + for (++parent; parent != certs.end(); ++iter, ++parent) { + LogDebug("Certificate validation (CN:" << + (*iter)->getOneLine() << ")"); + LogDebug("Parent certificate (CN:" << + (*parent)->getOneLine() << ")"); + statusSet.add(validateCertificate(*iter, *parent)); + if ((0 == minValidity || minValidity > m_responseValidity) && + m_responseValidity > 0) + { + minValidity = m_responseValidity; + } + } + m_responseValidity = minValidity; + + return statusSet; +} + +VerificationStatus OCSP::checkEndEntity( + const CertificateCollection &chain) +{ + const char *defResponderURI = getenv(OCSP::DEFAULT_RESPONDER_URI_ENV); + + VerificationStatusSet verSet; + if (defResponderURI) { + setUseDefaultResponder(true); + setDefaultResponder(defResponderURI); + } + + // this is temporary fix. it must be rewriten + CertificateList clst; + if (chain.isChain() && chain.size() >= 2) { + CertificateList::const_iterator icert = chain.begin(); + clst.push_back(*icert); + ++icert; + clst.push_back(*icert); + } + verSet += validateCertificateList(clst); + + return verSet.convertToStatus(); +} + +VerificationStatus OCSP::validateCertificate(CertificatePtr argCert, + CertificatePtr argIssuer) +{ + using namespace SoupWrapper; + + Assert(!!argCert); + Assert(!!argIssuer); + + Try { + DPL::OptionalString uri; + + if (!m_bUseDefResponder) { + uri = argCert->getOCSPURL(); + if (!uri) { + return VERIFICATION_STATUS_NOT_SUPPORT; + } + } else { + if (m_strResponderURI.empty()) { + ThrowMsg(Exception::VerificationError, + "Default responder is not set"); + } + LogWarning("Default responder will be used"); + + uri = m_strResponderURI; + } + + // creates a request + CreateRequestResult newRequest = createRequest(argCert, argIssuer); + if (!newRequest.success) { + ThrowMsg(Exception::VerificationError, "Request creation failed"); + } + + // SSLSmartContainer certIdCont(certId); + // this smart ptr is commented out in purpose. request + // manages certIdmemory (which was done in createRequest above) + SSLSmartContainer requestCont(newRequest.ocspRequest); + + SoupMessageSendBase::RequestStatus requestStatus; + requestStatus = sendOcspRequest(requestCont, uri); + + if (requestStatus != SoupMessageSendBase::REQUEST_STATUS_OK) { + return VERIFICATION_STATUS_CONNECTION_FAILED; + } + + // Response is m_soupMessage, convert it to OCSP_RESPONSE + OcspResponse response = convertToResponse(); + + if (!response.first) { + ThrowMsg(OCSP::Exception::VerificationError, + "OCSP: failed to convert mem buffer to OCSP_RESPONSE"); + } + + SSLSmartContainer responseCont(response.second); + // verify response eg. check response status, + // validate responder certificate + validateResponse(requestCont, + responseCont, + newRequest.ocspCertId); + } Catch(Exception::ConnectionError) { + LogWarning("OCSP: ConnectionError"); + return VERIFICATION_STATUS_CONNECTION_FAILED; + } Catch(Exception::CertificateRevoked) { + LogWarning("OCSP: Revoked"); + return VERIFICATION_STATUS_REVOKED; + } Catch(Exception::CertificateUnknown) { + LogWarning("OCSP: Unknown"); + return VERIFICATION_STATUS_UNKNOWN; + } Catch(Exception::VerificationError) { + LogWarning("OCSP: Verification error"); + return VERIFICATION_STATUS_VERIFICATION_ERROR; + } Catch(Exception::Base) { + LogWarning("OCSP: Error"); + return VERIFICATION_STATUS_ERROR; + } + LogWarning("OCSP: Good"); + return VERIFICATION_STATUS_GOOD; +} + +OCSP::CreateRequestResult OCSP::createRequest(CertificatePtr argCert, + CertificatePtr argIssuer) +{ + OCSP_REQUEST* newRequest = OCSP_REQUEST_new(); + + if (!newRequest) { + LogWarning("OCSP: Failed to create a request"); + return CreateRequestResult(); + } + + SSLSmartContainer requestCont(newRequest); + + OCSP_CERTID* certId = addSerial(argCert, argIssuer); + + if (!certId) { + LogWarning("OCSP: Unable to create a serial id"); + return CreateRequestResult(); + } + SSLSmartContainer certIdCont(certId); + + // Inserting certificate ID to request + if (!OCSP_request_add0_id(requestCont, certIdCont)) { + LogWarning("OCSP: Unable to create a certificate id"); + return CreateRequestResult(); + } + + if (m_bUseNonce) { + OCSP_request_add1_nonce(requestCont, 0, -1); + } + + if (m_bSignRequest) { + if (!m_pSignCert || !m_pSignKey) { + LogWarning("OCSP: Unable to sign request if " + "SignCert or SignKey was not set"); + return CreateRequestResult(); + } + + if (!OCSP_request_sign(requestCont, + m_pSignCert->getX509(), + m_pSignKey, + m_pRequestDigestAlg, + 0, + 0)) + { + LogWarning("OCSP: Unable to sign request"); + return CreateRequestResult(); + } + } + return CreateRequestResult(true, + requestCont.DetachPtr(), + certIdCont.DetachPtr()); +} + +OCSP_CERTID* OCSP::addSerial(CertificatePtr argCert, + CertificatePtr argIssuer) +{ + X509_NAME* iname = X509_get_subject_name(argIssuer->getX509()); + ASN1_BIT_STRING* ikey = X509_get0_pubkey_bitstr(argIssuer->getX509()); + ASN1_INTEGER* serial = X509_get_serialNumber(argCert->getX509()); + + return OCSP_cert_id_new(m_pCertIdDigestAlg, iname, ikey, serial); +} + +void OCSP::setDigestAlgorithmForCertId(DigestAlgorithm alg) +{ + DigestAlgorithmMap::const_iterator cit = m_sDigestAlgMap.find(alg); + + if (cit != m_sDigestAlgMap.end()) { + m_pCertIdDigestAlg = cit->second; + } else { + LogDebug("Request for unsupported CertId digest algorithm" + "ignored!"); + } +} + +void OCSP::setDigestAlgorithmForRequest(DigestAlgorithm alg) +{ + DigestAlgorithmMap::const_iterator cit = m_sDigestAlgMap.find(alg); + + if (cit != m_sDigestAlgMap.end()) { + m_pRequestDigestAlg = cit->second; + } else { + LogDebug("Request for unsupported OCSP request digest algorithm" + "ignored!"); + } +} + +void OCSP::setTrustedStore(const CertificateList& certs) +{ + X509_STORE *store = X509_STORE_new(); + m_pTrustedStore = store; + // create a trusted store basing on certificate chain from a signature + FOREACH(iter, certs) { + X509_STORE_add_cert(store, (*iter)->getX509()); + } +} + +void OCSP::validateResponse(OCSP_REQUEST* argRequest, + OCSP_RESPONSE* argResponse, + OCSP_CERTID* argCertId) +{ + int result = OCSP_response_status(argResponse); + + if (result != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + handleInvalidResponse(result); + ThrowMsg(Exception::VerificationError, "OCSP_response_status failed"); + } + + // get response object + OCSP_BASICRESP* basic = OCSP_response_get1_basic(argResponse); + if (!basic) { + ThrowMsg(Exception::VerificationError, + "OCSP: Unable to get a BASICRESP object."); + } + + SSLSmartContainer basicRespCont(basic); + if (m_bUseNonce && OCSP_check_nonce(argRequest, basicRespCont) <= 0) { + ThrowMsg(Exception::VerificationError, "OCSP: Invalid nonce"); + } + + if (!verifyResponse(basic)) { + ThrowMsg(Exception::VerificationError, + "Unable to verify the OCSP responder's certificate"); + } + + checkRevocationStatus(basicRespCont, argCertId); +} + +bool OCSP::verifyResponse(OCSP_BASICRESP* basic) +{ + Assert(m_pTrustedStore); + // verify ocsp response + int response = OCSP_basic_verify(basic, NULL, m_pTrustedStore, 0); + if (response <= 0) { + LogWarning("OCSP verification failed"); + } + + return response > 0; +} + +void OCSP::checkRevocationStatus(OCSP_BASICRESP* basic, + OCSP_CERTID* id) +{ + ASN1_GENERALIZEDTIME* producedAt; + ASN1_GENERALIZEDTIME* thisUpdate; + ASN1_GENERALIZEDTIME* nextUpdate; + int reason; + int status; + + m_responseValidity = 0; + + if (!OCSP_resp_find_status(basic, + id, + &status, + &reason, + &producedAt, + &thisUpdate, + &nextUpdate)) + { + ThrowMsg(Exception::VerificationError, + "OCSP: Failed to find certificate status."); + } + + if (!OCSP_check_validity(thisUpdate, + nextUpdate, + MaxValidatyPeriodInSeconds, + MaxAge)) + { + ThrowMsg(Exception::VerificationError, + "OCSP: Failed to check certificate validate."); + } + + if (nextUpdate) { + asn1GeneralizedTimeToTimeT(nextUpdate,&m_responseValidity); + time_t now; + time(&now); + LogDebug("Time of next OCSP update got from server: " << + m_responseValidity); + LogDebug("Expires in: " << (m_responseValidity - now)); + LogDebug("Original: " << nextUpdate->data); + } + + switch (status) { + case V_OCSP_CERTSTATUS_GOOD: + return; + case V_OCSP_CERTSTATUS_REVOKED: + ThrowMsg(Exception::CertificateRevoked, "Certificate is Revoked"); + case V_OCSP_CERTSTATUS_UNKNOWN: + ThrowMsg(Exception::CertificateUnknown, "Certificate is Unknown"); + default: + Assert(false && "Invalid status"); + } +} + +OCSP::OcspResponse OCSP::convertToResponse() +{ + using namespace SoupWrapper; + + // convert memory buffer to ocsp response object + BUF_MEM res_bmem; + OCSP_RESPONSE* response; + + SoupMessageSendBase::MessageBuffer buffer = m_soupMessage.getResponse(); + + res_bmem.length = buffer.size(); + res_bmem.data = &buffer[0]; + res_bmem.max = buffer.size(); + + BIO* res_mem_bio = BIO_new(BIO_s_mem()); + BIO_set_mem_buf(res_mem_bio, &res_bmem, BIO_NOCLOSE); + + response = d2i_OCSP_RESPONSE_bio(res_mem_bio, NULL); + BIO_free_all(res_mem_bio); + + if (!response) { + LogWarning("OCSP: Failed to convert OCSP Response to DER format"); + return std::make_pair(false, static_cast(NULL)); + } + + return std::make_pair(true, response); +} + +void OCSP::handleInvalidResponse(int result) +{ + switch (result) { + case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST: + LogWarning("OCSP: Server returns " + "OCSP_RESPONSE_STATUS_MALFORMEDREQUEST status"); + break; + case OCSP_RESPONSE_STATUS_INTERNALERROR: + LogWarning("OCSP: Server returns " + "OCSP_RESPONSE_STATUS_INTERNALERROR status"); + break; + case OCSP_RESPONSE_STATUS_TRYLATER: + LogWarning("OCSP: Server returns " + "OCSP_RESPONSE_STATUS_TRYLATER status"); + break; + case OCSP_RESPONSE_STATUS_SIGREQUIRED: + LogWarning("OCSP: Server returns " + "OCSP_RESPONSE_STATUS_SIGREQUIRED status"); + break; + case OCSP_RESPONSE_STATUS_UNAUTHORIZED: + LogWarning("OCSP: Server returns " + "OCSP_RESPONSE_STATUS_UNAUTHORIZED status"); + break; + default: + Assert(false && "Invalid result value"); + } +} +} // namespace ValidationCore diff --git a/vcore/src/vcore/OCSP.h b/vcore/src/vcore/OCSP.h new file mode 100644 index 0000000..5f60da0 --- /dev/null +++ b/vcore/src/vcore/OCSP.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Tomasz Morawski(t.morawski@samsung.com) + * @author Michal Ciepielski(m.ciepielski@samsung.com) + * @author Piotr Marcinkiewicz(p.marcinkiew@samsung.com) + * @version 0.4 + * @file OCPS.h + * @brief Routines for certificate validation over OCSP + */ + +#ifndef WRT_ENGINE_SRC_VALIDATION_CORE_ENGINE_OCSP_H_ +#define WRT_ENGINE_SRC_VALIDATION_CORE_ENGINE_OCSP_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "OCSPCertMgrUtil.h" +#include "CertificateCollection.h" +#include "CertificateStorage.h" +#include "VerificationStatus.h" +#include "SSLContainers.h" + +#include "SoupMessageSendBase.h" +#include "SoupMessageSendSync.h" +/* + * The WRT MUST NOT allow installation of widgets with revoked signatures. + * + * The WRT MUST NOT allow use of widgets with revoked signatures. + * + * The WRT MUST support checking for revocation of widget signatures via + * OCSP [RFC 2560] at widget installation time, according to the following: + * + * At widget installation time, the WRT shall make several attempts + * (5 attempts at 6 seconds apart recommended) to establish contact with + * the OCSP server. + * + * If connectivity is successful and the application is validated, the + * installation process shall continue. + * + * If connectivity is successful and if the widget signature is + * determined to be revoked, the WRT shall issue a suitable error message + * and cancel installation. + * + * If connectivity is successful and revocation status is unknown or if + * connectivity is unsuccessful, the user must be notified that the + * widget was unable to be installed as trusted - the certification of + * the widget signature has not been validated -, and prompt the user to allow + * the user to install the widget as an untrusted application, or reject + * the installation. + * + * The WRT MUST support checking for revocation of widget signatures via OCSP + * [RFC 2560] at widget runtime. + * + * The WRT MUST support OCSP access policy. + */ + +namespace ValidationCore { + +class OCSP +// : public RevocationCheckerBase +{ + public: + static const char* DEFAULT_RESPONDER_URI_ENV; + + VerificationStatus checkEndEntity(const CertificateCollection &certList); + OCSP(); + + enum DigestAlgorithm + { + SHA1, + SHA224, + SHA256, + SHA384, + SHA512 + }; + typedef std::map DigestAlgorithmMap; + /** + * Sets digest algorithm for certid in ocsp request + */ + void setDigestAlgorithmForCertId(DigestAlgorithm alg); + + /** + * Sets digest algorithm for certid in ocsp request + */ + void setDigestAlgorithmForRequest(DigestAlgorithm alg); + + void setTrustedStore(const CertificateList& certs); + + VerificationStatusSet validateCertificateList(const CertificateList &certs); + + VerificationStatus validateCertificate(CertificatePtr argCert, + CertificatePtr argIssuer); + + void setDefaultResponder(const char* uri) + { + Assert(uri); + m_strResponderURI = DPL::FromUTF8String(uri); + } + + void setUseDefaultResponder(bool value) + { + m_bUseDefResponder = value; + } + + /** + * @return time when response will become invalid - for list of + * certificates, this is the minimum of all validities; value is + * valid only for not-revoked certificates (non error validation result) + */ + time_t getResponseValidity() + { + return m_responseValidity; + } + + private: + typedef WRT::ScopedGPointer ScopedSoupSession; + typedef WRT::ScopedGPointer ScopedSoupMessage; + + void handleInvalidResponse(int result); + void sendHTTPRequest(ScopedSoupSession& session, + ScopedSoupMessage& msg, + const char* host, + const char* port, + const char* path, + char* requestBuffer, + size_t reqestSize); + void sendRequest(const std::string& uri, + char* requestBuffer, + size_t requestSize, + char** responseBuffer, + size_t* responseSize); + + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, ConnectionError) + DECLARE_EXCEPTION_TYPE(Base, CertificateRevoked) + DECLARE_EXCEPTION_TYPE(Base, CertificateUnknown) + DECLARE_EXCEPTION_TYPE(Base, VerificationError) + DECLARE_EXCEPTION_TYPE(Base, RetrieveCertFromStoreError) + DECLARE_EXCEPTION_TYPE(Base, VerificationNotSupport) + }; + + const EVP_MD* m_pCertIdDigestAlg; + const EVP_MD* m_pRequestDigestAlg; + static DigestAlgorithmMap m_sDigestAlgMap; + + typedef std::pair HttpResponseBuffer; + + SoupWrapper::SoupMessageSendBase::RequestStatus sendOcspRequest( + OCSP_REQUEST* argRequest, + const DPL::OptionalString& argUri); + + //! Validates a single certificate + /*! + * @param cert The certificate to check + * @param issuer A certificate used to sign the certificate to check. + */ + + struct CreateRequestResult + { + bool success; + OCSP_REQUEST* ocspRequest; + OCSP_CERTID* ocspCertId; + CreateRequestResult(bool argSuccess = false, + OCSP_REQUEST* argOcspRequest = NULL, + OCSP_CERTID* argOcspCertId = NULL) : + success(argSuccess), + ocspRequest(argOcspRequest), + ocspCertId(argOcspCertId) + { + } + }; + + //! Creates a OCSP request + /*! + * @param request Returns created OCSP_REQUEST + * @param id Returns CertId that is used to find proper OCSP result in + * the OCSP response (@see checkRevocationStatus for more details). + * + */ + CreateRequestResult createRequest(CertificatePtr argCert, + CertificatePtr argIssuer); + + OCSP_CERTID* addSerial(CertificatePtr argCert, + CertificatePtr argIssuer); + + void validateResponse(OCSP_REQUEST* argRequest, + OCSP_RESPONSE* argResponse, + OCSP_CERTID* argCertId); + + //! Create a X509 store + bool verifyResponse(OCSP_BASICRESP* argResponse); + + void checkRevocationStatus(OCSP_BASICRESP* argBasicResponse, + OCSP_CERTID* argCertId); + + typedef std::pair OcspResponse; + + OcspResponse convertToResponse(); + + time_t m_responseValidity; + bool m_bUseNonce; + bool m_bUseDefResponder; + DPL::String m_strResponderURI; + bool m_bSignRequest; + EVP_PKEY* m_pSignKey; + CertificatePtr m_pSignCert; + SSLSmartContainer m_pTrustedStore; + SoupWrapper::SoupMessageSendSync m_soupMessage; +}; +} // ValidationCore + +#endif //ifndef WRT_ENGINE_SRC_VALIDATION_CORE_ENGINE_OCSP_H_ diff --git a/vcore/src/vcore/OCSPCertMgrUtil.cpp b/vcore/src/vcore/OCSPCertMgrUtil.cpp new file mode 100644 index 0000000..794ecfa --- /dev/null +++ b/vcore/src/vcore/OCSPCertMgrUtil.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2011 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. + */ +/* + * @author Michal Ciepielski(m.ciepielski@samsung.com) + * @version 0.3 + * @brief + */ + +#include "OCSPCertMgrUtil.h" +#include "SSLContainers.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace { +const int MAX_BUF = 1024; + +struct ContextDeleter +{ + typedef CERT_CONTEXT* Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type context) + { + if (context) { + cert_svc_cert_context_final(context); + } + } +}; +} + +namespace ValidationCore { +namespace OCSPCertMgrUtil { +/* + * TODO This API function should be changed to: + * CertifiatePtr getCertFromStore(const std::string &subject); + * + * All of cert_svc function could return error because input + * data are corruped. That's why I dont want to throw exceptions + * in this function. + */ +void getCertFromStore(X509_NAME *subject, + X509 **xcert) +{ + if (!xcert || *xcert || !subject) { + LogError("Invalid input!"); + return; + } + + typedef DPL::ScopedResource ScopedContext; + + int result; + char buffer[MAX_BUF]; + const unsigned char* ptr = NULL; + X509 *pCertificate = NULL; + cert_svc_filename_list *fileList = NULL; + + X509_NAME_oneline(subject, buffer, MAX_BUF); + + ScopedContext ctx(cert_svc_cert_context_init()); + if (ctx.Get() == NULL) { + LogWarning("Error in cert_svc_cert_context_init."); + return; + } + + LogDebug("Search certificate with subject: " << buffer); + result = cert_svc_search_certificate(ctx.Get(), SUBJECT_STR, buffer); + LogDebug("Search finished!"); + + if (CERT_SVC_ERR_NO_ERROR != result) { + LogWarning("Error during certificate search"); + return; + } + + fileList = ctx.Get()->fileNames; + + if (fileList == NULL) { + LogDebug("No certificate found"); + return; + } + + if (fileList->filename == NULL) { + LogWarning("Empty filename"); + return; + } + + LogDebug("Found cert file: " << fileList->filename); + ScopedContext ctx2(cert_svc_cert_context_init()); + + if (ctx2.Get() == NULL) { + LogWarning("Error in cert_svc_cert_context_init."); + return; + } + + // TODO add read_certifcate_from_file function to Certificate.h + if (CERT_SVC_ERR_NO_ERROR != + cert_svc_load_file_to_context(ctx2.Get(), fileList->filename)) { + LogWarning("Error in cert_svc_load_file_to_context"); + return; + } + + ptr = ctx2.Get()->certBuf->data; + // create a certificate from mem buff + pCertificate = d2i_X509(NULL, &ptr, ctx2.Get()->certBuf->size); + + if (pCertificate == NULL) { + LogWarning("Error during certificate conversion in d2i_X509"); + return; + } + + *xcert = pCertificate; + if (fileList->next != NULL) { + LogError("There is more then one certificate with same subject :/"); + // TODO Implement me. + for (fileList = fileList->next; + fileList != NULL; + fileList = fileList->next) { + LogError( + "Additional certificate with same subject: " << + fileList->filename); + } + } +} + +CertificatePtr getParentFromStore(const CertificatePtr &certificate) +{ + Assert(certificate.Get()); + X509* rawPtr = certificate->getX509(); + + /* TODO Add getIssuerName function to Certificate.h */ + X509_NAME *name = X509_get_issuer_name(rawPtr); + + X509* rawTemp = NULL; + getCertFromStore(name, &rawTemp); + + if (rawTemp == NULL) { + return CertificatePtr(); + } + + SSLSmartContainer scope(rawTemp); + return CertificatePtr(new Certificate(rawTemp)); +} + +CertificateList completeCertificateChain(const CertificateList &certificateList) +{ + CertificateList result = certificateList; + CertificatePtr last = result.back(); + if (last->isSignedBy(last)) { + return result; + } + CertificatePtr parent = getParentFromStore(last); + if (parent.Get()) { + result.push_back(parent); + } + return result; +} +} // namespace OCSPCertMgrUtil +} // namespace ValidationCore diff --git a/vcore/src/vcore/OCSPCertMgrUtil.h b/vcore/src/vcore/OCSPCertMgrUtil.h new file mode 100644 index 0000000..a93a42e --- /dev/null +++ b/vcore/src/vcore/OCSPCertMgrUtil.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 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. + */ +/* + * @author Tomasz Morawski(t.morawski@samsung.com) + * @author Michal Ciepielski(m.ciepielski@samsung.com) + * @version 0.2 + * @brief + */ + +#ifndef _WRT_OCSP_CERT_MGR_UTIL_H_ +#define _WRT_OCSP_CERT_MGR_UTIL_H_ + +#include + +#include "Certificate.h" + +namespace ValidationCore { +namespace OCSPCertMgrUtil { +void getCertFromStore(X509_NAME *subject, + X509 **xcert); +CertificatePtr getParentFromStore(const CertificatePtr &certificate); +/* + * Look for "parent" certificate from store. + * It returns new certificate chain. + */ +CertificateList completeCertificateChain(const CertificateList &certList); +} // namespace OCSPCertMgrUtil +} // namespace ValidationCore +#endif + diff --git a/vcore/src/vcore/OCSPUtil.c b/vcore/src/vcore/OCSPUtil.c new file mode 100644 index 0000000..451884a --- /dev/null +++ b/vcore/src/vcore/OCSPUtil.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011 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. + */ +/* + * @author Tomasz Morawski(t.morawski@samsung.com) + * @version 0.1 + * @brief + */ + +#include + +/* + * This function is needed to fix "Invalid conversion from void* to unsigned char*" + * C++ compiler error during calling i2d_OCSP_REQUEST_bio macro + */ +int convertToBuffer(OCSP_REQUEST *req, char **buf, int *size) { + BIO *req_mem_bio; + BUF_MEM req_bmem; + + /* + * size and membuffer for request + */ + *size = i2d_OCSP_REQUEST(req, NULL); + *buf = (char*) malloc(*size); + + if (!*buf) + return 0; + + /* copy request into buffer */ + req_bmem.length = 0; + req_bmem.data = *buf; + req_bmem.max = *size; + + /* + * create a new buffer using openssl + */ + req_mem_bio = BIO_new(BIO_s_mem()); + + if (!req_mem_bio) { + /* + * creation failed, return + */ + free(*buf); + *buf = NULL; + return 0; + } + + BIO_set_mem_buf(req_mem_bio, &req_bmem, BIO_NOCLOSE); + + /* + * prepare request + */ + if (i2d_OCSP_REQUEST_bio(req_mem_bio, req) <= 0) { + free(*buf); + *buf = NULL; + BIO_free_all(req_mem_bio); + return 0; + } + + /* + * check consistency + */ + if (*size != ((int)req_bmem.length) || req_bmem.length != req_bmem.max) + { + free(*buf); + *buf = NULL; + BIO_free_all(req_mem_bio); + return 0; + } + + /* + * free all reserved memory + */ + BIO_free_all(req_mem_bio); + + /* + * and return success + */ + return 1; +} diff --git a/vcore/src/vcore/ParserSchema.h b/vcore/src/vcore/ParserSchema.h new file mode 100644 index 0000000..6fabff8 --- /dev/null +++ b/vcore/src/vcore/ParserSchema.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2011 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 ParserSchema.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ +#ifndef _PARSERSCHEMA_H_ +#define _PARSERSCHEMA_H_ + +#include +#include + +#include + +#include "SaxReader.h" + +namespace ValidationCore { +namespace ParserSchemaException { +DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) +DECLARE_EXCEPTION_TYPE(Base, XmlReaderError) +DECLARE_EXCEPTION_TYPE(Base, CertificateLoaderError) +DECLARE_EXCEPTION_TYPE(Base, UnsupportedAlgorithm) +DECLARE_EXCEPTION_TYPE(Base, UnsupportedValue) +} + +template +class ParserSchema +{ + public: + struct TagDescription + { + TagDescription(const std::string &tag, + const std::string & xmlNamespace) : + tagName(tag), + namespaceUri(xmlNamespace) + { + } + + std::string tagName; + std::string namespaceUri; + + bool operator<(const TagDescription &second) const + { + if (tagName < second.tagName) { + return true; + } + if (tagName > second.tagName) { + return false; + } + if (namespaceUri < second.namespaceUri) { + return true; + } + return false; + } + }; + + ParserSchema(ParserType * parser) : + m_functions(parser) + { + } + + virtual ~ParserSchema() + { + } + + void initialize(const std::string &filename, + bool defaultArgs, + SaxReader::ValidationType valType, + const std::string &xmlschema) + { + Try + { + m_reader.initialize(filename, defaultArgs, valType, xmlschema); + } + Catch(SaxReader::Exception::Base) + { + ReThrowMsg(ParserSchemaException::XmlReaderError, "XmlReaderError"); + } + } + + void deinitialize() + { + m_reader.deinitialize(); + } + + void read(DataType &dataContainer) + { + Try { + while (m_reader.next()) { + switch (m_reader.type()) { + case SaxReader::NODE_BEGIN: + beginNode(dataContainer); + break; + case SaxReader::NODE_END: + endNode(dataContainer); + break; + case SaxReader::NODE_TEXT: + textNode(dataContainer); + break; + default: + // LogInfo("Unknown Type Node"); + break; + } + } + } + Catch(SaxReader::Exception::Base) + { + ReThrowMsg(ParserSchemaException::XmlReaderError, "XmlReaderError"); + } + } + + typedef void (ParserType::*FunctionPtr)(DataType &data); + typedef std::map FunctionMap; + + void addBeginTagCallback(const std::string &tag, + const std::string &namespaceUri, + FunctionPtr function) + { + TagDescription desc(tag, namespaceUri); + m_beginFunctionMap[desc] = function; + } + + void addEndTagCallback(const std::string &tag, + const std::string &namespaceUri, + FunctionPtr function) + { + TagDescription desc(tag, namespaceUri); + m_endFunctionMap[desc] = function; + } + + SaxReader& getReader(void) + { + return m_reader; + } + + std::string& getText(void) + { + return m_textNode; + } + + protected: + void beginNode(DataType &dataContainer) + { + TagDescription desc(m_reader.name(), m_reader.namespaceURI()); + FunctionPtr fun = m_beginFunctionMap[desc]; + + if (fun == 0) { + LogDebug("No function found for xml tag: " << m_reader.name()); + return; + } + + (m_functions->*fun)(dataContainer); + } + + void endNode(DataType &dataContainer) + { + TagDescription desc(m_reader.name(), m_reader.namespaceURI()); + FunctionPtr fun = m_endFunctionMap[desc]; + + if (fun == 0) { + LogDebug("No function found for xml tag: " << m_reader.name()); + return; + } + + (m_functions->*fun)(dataContainer); + } + + void textNode(DataType &dataContainer) + { + (void)dataContainer; + m_textNode = m_reader.value(); + } + + ParserType *m_functions; + + SaxReader m_reader; + FunctionMap m_beginFunctionMap; + FunctionMap m_endFunctionMap; + + // temporary values require due parsing textNode + std::string m_textNode; +}; +} // namespace ValidationCore +#endif diff --git a/vcore/src/vcore/ReferenceValidator.cpp b/vcore/src/vcore/ReferenceValidator.cpp new file mode 100644 index 0000000..d56eea8 --- /dev/null +++ b/vcore/src/vcore/ReferenceValidator.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011 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. + */ +#include +#include +#include +#include + +#include +#include + +#include "Base64.h" +#include "ReferenceValidator.h" + +namespace { +const char *SPECIAL_SYMBOL_CURRENT_DIR = "."; +const char *SPECIAL_SYMBOL_UPPER_DIR = ".."; +const char *SPECIAL_SYMBOL_AUTHOR_SIGNATURE_FILE = "author-signature.xml"; +const char *REGEXP_DISTRIBUTOR_SIGNATURE = "^signature[1-9][0-9]*\\.xml"; +} // namespace anonymous + +namespace ValidationCore { +ReferenceValidator::ReferenceValidator(const std::string &dirpath) : + m_dirpath(dirpath), + m_signatureRegexp(REGEXP_DISTRIBUTOR_SIGNATURE) +{ +} + +ReferenceValidator::Result ReferenceValidator::checkReferences( + const SignatureData &signatureData) +{ + return dfsCheckDirectories(signatureData, std::string()); +} + +ReferenceValidator::Result ReferenceValidator::dfsCheckDirectories( + const SignatureData &signatureData, + const std::string &directory) +{ + DIR *dp; + struct dirent *dirp; + std::string currentDir = m_dirpath + directory; + + if ((dp = opendir(currentDir.c_str())) == NULL) { + LogError("Error opening directory: " << currentDir.c_str()); + m_errorDescription = currentDir; + return ERROR_OPENING_DIR; + } + + for (errno = 0; (dirp = readdir(dp)) != NULL; errno = 0) { + if (!strcmp(dirp->d_name, SPECIAL_SYMBOL_CURRENT_DIR)) { + continue; + } + + if (!strcmp(dirp->d_name, SPECIAL_SYMBOL_UPPER_DIR)) { + continue; + } + + if (currentDir == m_dirpath && dirp->d_type == DT_REG && + !strcmp(dirp->d_name, + SPECIAL_SYMBOL_AUTHOR_SIGNATURE_FILE) && + signatureData.isAuthorSignature()) { + continue; + } + + if (currentDir == m_dirpath && dirp->d_type == DT_REG && + isDistributorSignature(dirp->d_name)) { + continue; + } + + if (dirp->d_type == DT_DIR) { + LogDebug("Open directory: " << (directory + dirp->d_name)); + std::string tmp_directory = directory + dirp->d_name + "/"; + Result result = dfsCheckDirectories(signatureData, tmp_directory); + if (result != NO_ERROR) { + closedir(dp); + return result; + } + } else if (dirp->d_type == DT_REG) { + LogDebug("Found file: " << (directory + dirp->d_name)); + const ReferenceSet &referenceSet = signatureData.getReferenceSet(); + if (referenceSet.end() == + referenceSet.find(directory + dirp->d_name)) { + closedir(dp); + m_errorDescription = directory + dirp->d_name; + return ERROR_REFERENCE_NOT_FOUND; + } + } else { + LogError("Unknown file type."); + closedir(dp); + m_errorDescription = directory + dirp->d_name; + return ERROR_UNSUPPORTED_FILE_TYPE; + } + } + + if (errno != 0) { + m_errorDescription = DPL::GetErrnoString(); + LogError("readdir failed. Errno code: " << errno << + " Description: " << m_errorDescription); + closedir(dp); + return ERROR_READING_DIR; + } + + closedir(dp); + + return NO_ERROR; +} +} diff --git a/vcore/src/vcore/ReferenceValidator.h b/vcore/src/vcore/ReferenceValidator.h new file mode 100644 index 0000000..5f05095 --- /dev/null +++ b/vcore/src/vcore/ReferenceValidator.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 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. + */ +#ifndef _REFERENCEVALIDATOR_H_ +#define _REFERENCEVALIDATOR_H_ + +#include + +#include "SignatureData.h" + +namespace ValidationCore { +class ReferenceValidator +{ + public: + enum Result + { + NO_ERROR = 0, + ERROR_OPENING_DIR, + ERROR_READING_DIR, + ERROR_UNSUPPORTED_FILE_TYPE, + ERROR_REFERENCE_NOT_FOUND + }; + + ReferenceValidator(const std::string &dirpath); + + virtual ~ReferenceValidator() + { + } + + Result checkReferences(const SignatureData &signatureData); + + private: + + Result dfsCheckDirectories(const SignatureData &signatureData, + const std::string &directory); + + inline bool isDistributorSignature(const char *cstring) const + { + return m_signatureRegexp.FullMatch(cstring); + } + + std::string m_dirpath; + std::string m_errorDescription; + pcrecpp::RE m_signatureRegexp; +}; +} + +#endif // _REFERENCEVALIDATOR_H_ diff --git a/vcore/src/vcore/RevocationCheckerBase.cpp b/vcore/src/vcore/RevocationCheckerBase.cpp new file mode 100644 index 0000000..f0e43e7 --- /dev/null +++ b/vcore/src/vcore/RevocationCheckerBase.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Piotr Marcinkiewicz(p.marcinkiew@samsung.com) + * @version 0.4 + * @file CommonCertValidator.cpp + * @brief Common routines for certificate validation over OCSP and CRL + */ + +#include "RevocationCheckerBase.h" + +#include + +#include + +#include + +#include "Certificate.h" +#include "CertificateCollection.h" + +namespace { +const char DefaultBundlePatch[] = "/opt/etc/ssl/certs/ca-certificates.crt"; +} //Anonymous name space + +namespace ValidationCore { +CertificatePtr RevocationCheckerBase::loadPEMFile(const char* fileName) +{ + DPL::ScopedFClose fd(fopen(fileName, "rb")); + + // no such file, return NULL + if (!fd.Get()) { + return CertificatePtr(); + } + + // create a new X509 certificate basing on file + CertificatePtr cert(new Certificate(PEM_read_X509(fd.Get(), + NULL, + NULL, + NULL))); + return cert; +} + +bool RevocationCheckerBase::sortCertList(CertificateList &lCertificates) +{ + CertificateCollection collection; + collection.load(lCertificates); + + if (collection.sort()) { + lCertificates = collection.getChain(); + return true; + } + return false; +} + +} // ValidationCore diff --git a/vcore/src/vcore/RevocationCheckerBase.h b/vcore/src/vcore/RevocationCheckerBase.h new file mode 100644 index 0000000..3ce934d --- /dev/null +++ b/vcore/src/vcore/RevocationCheckerBase.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Piotr Marcinkiewicz(p.marcinkiew@samsung.com) + * @version 0.4 + * @file CommonCertValidator.h + * @brief Common routines for certificate validation over OCSP and CRL + */ + +#ifndef WRT_ENGINE_SRC_VALIDATION_CORE_REVOCATIONCHECKERBASE_H_ +#define WRT_ENGINE_SRC_VALIDATION_CORE_REVOCATIONCHECKERBASE_H_ + +#include + +#include "Certificate.h" + +namespace ValidationCore { +class RevocationCheckerBase +{ + public: + //! Loads a PEM file and returns X509 certificate object. + static CertificatePtr loadPEMFile(const char* path); + + //! Sorts a list of certficates and verifies them if they form + //! a valid chain + static bool sortCertList(CertificateList &cert) __attribute__((deprecated)); +}; +} // ValidationCore + +#endif //ifndef WRT_ENGINE_SRC_VALIDATION_CORE_REVOCATIONCHECKERBASE_H_ + diff --git a/vcore/src/vcore/SSLContainers.h b/vcore/src/vcore/SSLContainers.h new file mode 100644 index 0000000..e18cb00 --- /dev/null +++ b/vcore/src/vcore/SSLContainers.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2011 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. + */ +#ifndef _SSLCONTAINERS_H +#define _SSLCONTAINERS_H + +#include +#include + +/* + * default deleter functor with no overloaded operator() + */ +template +struct MySSLFree {}; + +/* + * macro for defining custom deleters for openssl structs + * usage DECLARE_DELETER(OpenSSLType) + */ +#define DECLARE_DELETER(Type) template<> \ + struct MySSLFree \ + { \ + void operator() (Type* p) \ + { \ + Type ## _free(p); \ + } \ + \ + }; + +/* + * declare custom deleter for X509 structs + */ +DECLARE_DELETER(X509) +/* + * declare custom deleter for OCSP_REQUEST structs + */ +DECLARE_DELETER(OCSP_REQUEST) +/* + * declare custom deleter for OCSP_RESPONSE structs + */ +DECLARE_DELETER(OCSP_RESPONSE) +/* + * declare custom deleter for OCSP_CERTID structs + */ +DECLARE_DELETER(OCSP_CERTID) +/* + * declare custom deleter for OCSP_BASICRESP structs + */ +DECLARE_DELETER(OCSP_BASICRESP) +/* + * declare custom deleter for X509_STORE structs + */ +DECLARE_DELETER(X509_STORE) + +/* + * undef it, so anyone could use that macro name + */ +#undef DECLARE_DELETER + +/* + * OpenSSL smart container + * usage SSLSmartContainer smartptr = ptrToOpenSSLType + * remember to add OpenSSLType to macro list few lines above + */ +template > +class SSLSmartContainer +{ + public: + SSLSmartContainer() : m_pData(NULL) + { + } + + /* + * explicit constructor, we don't want any auto casting + */ + explicit SSLSmartContainer(T* pData) + { + m_pData = pData; + } + + /* + * overloaded assignment operator + */ + SSLSmartContainer & operator=(SSLSmartContainer& pContainer) + { + /* + * check if no assignment was done before + */ + if (this != &pContainer) { + // if so, free internal data + deleter ssl_free; + ssl_free(m_pData); + + // and assign new + m_pData = pContainer.m_pData; + + pContainer.m_pData = NULL; + } + + return *this; + } + + SSLSmartContainer & operator=(T* pData) + { + /* + * check if no assignment was done before + */ + if (m_pData != pData) { + // if so, free internal data + deleter ssl_free; + ssl_free(m_pData); + + // and assign new + m_pData = pData; + } + + return *this; + } + + ~SSLSmartContainer() + { + deleter ssl_free; + ssl_free(m_pData); + } + + /* + * overloaded operators for standardptr - like usage + */ + SSLSmartContainer & operator*() + { + return *m_pData; + } + SSLSmartContainer* operator->() + { + return m_pData; + } + + /* + * auto cast to T operator + */ + operator T *() const { return m_pData; + } + + /* + * detachs internal pointer from smart pointer + */ + T* DetachPtr() + { + T* pData = m_pData; + m_pData = NULL; + return pData; + } + + private: + /* + * blocked assignment from another types operator + */ + template + T & operator = (S& pContainer) + { + return *this; + } + + /* + * internal data + */ + T* m_pData; +}; + +#endif /* _SSLCONTAINERS_H */ + diff --git a/vcore/src/vcore/SaxReader.cpp b/vcore/src/vcore/SaxReader.cpp new file mode 100644 index 0000000..5bef911 --- /dev/null +++ b/vcore/src/vcore/SaxReader.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2011 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 SaxReader.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief Simple c++ interface for libxml2. + */ +#include +#include +#include + +#include "SaxReader.h" + +namespace ValidationCore { +SaxReader::SaxReader() : + m_reader(0) +{ +} + +SaxReader::~SaxReader() +{ + if (m_reader) { + deinitialize(); + } +} + +void SaxReader::initialize(const std::string &filename, + bool defaultArgs, + ValidationType validate, + const std::string &schema) +{ + Assert(m_reader == 0 && "Double initialization of SaxReader"); + + LogDebug("SaxReader opening file: " << filename); + + /* + * create a new xml text reader + */ + m_reader = xmlNewTextReaderFilename(filename.c_str()); + + if (m_reader == NULL) { + /* + * no such file, return + */ + LogWarning("Error during opening file " << filename); + Throw(Exception::FileOpeningError); + } + if (validate == VALIDATION_XMLSCHEME && + xmlTextReaderSchemaValidate(m_reader, schema.c_str())) { + /* + * unable to turn on schema validation + */ + LogError("Turn on Schema validation failed."); + ThrowMsg(Exception::ParserInternalError, + "Turn on Scheme validation failed!"); + } + // Path to DTD schema is taken from xml file. + if (validate == VALIDATION_DTD && + xmlTextReaderSetParserProp(m_reader, XML_PARSER_VALIDATE, 1)) { + /* + * unable to turn on DTD validation + */ + LogError("Turn on DTD validation failed!"); + ThrowMsg(Exception::ParserInternalError, + "Turn on DTD validation failed!"); + } + if (defaultArgs && + xmlTextReaderSetParserProp(m_reader, XML_PARSER_DEFAULTATTRS, 1)) { + /* + * unable to turn on default arguments + */ + LogError("Turn on default arguments failed"); + ThrowMsg(Exception::ParserInternalError, + "Turn on Default Arguments failed!"); + } +} + +void SaxReader::deinitialize() +{ + xmlFreeTextReader(m_reader); + m_reader = 0; +} + +bool SaxReader::next() +{ + int res = xmlTextReaderRead(m_reader); + + if (0 == xmlTextReaderIsValid(m_reader)) { + LogWarning("Throw exception file not valid!"); + Throw(Exception::FileNotValid); + } + + if (res == 1) { + return true; + } + + if (res == 0) { + return false; + } + LogError("ParserInternalError"); + Throw(Exception::ParserInternalError); +} + +void SaxReader::next(const std::string &token) +{ + xmlTextReaderRead(m_reader); + if (0 == xmlTextReaderIsValid(m_reader)) { + /* + * invalid file + */ + LogWarning("Throw exception file not valid!"); + Throw(Exception::FileNotValid); + } + + xmlChar *name = xmlTextReaderName(m_reader); + + if (name == NULL) { + /* + * invalid file + */ + LogWarning("File not Valid"); + Throw(Exception::FileNotValid); + } + + if (token == reinterpret_cast(name)) { + xmlFree(name); + } else { + /* + * we encountered wrong token + */ + xmlFree(name); + LogWarning("Wrong Token"); + Throw(Exception::WrongToken); + } +} + +bool SaxReader::isEmpty(void) +{ + int ret = xmlTextReaderIsEmptyElement(m_reader); + if (-1 == ret) { + LogError("Parser Internal Error"); + Throw(Exception::ParserInternalErrorInEmptyQuery); + } + return ret; +} + +std::string SaxReader::attribute(const std::string &token, + ThrowType throwStatus) +{ + std::string value; + xmlChar *attr = xmlTextReaderGetAttribute(m_reader, BAD_CAST(token.c_str())); + if ((NULL == attr) && (throwStatus == THROW_DISABLE)) { + /* + * return empty string + */ + //TODO why not DPL::Optional? + return std::string(); + } + if (NULL == attr) { + /* + * error during read attribute + */ + LogError("Error in reading attribute."); + Throw(Exception::ParserInternalErrorInReadingAttribute); + } + + /* + * cast it to val and return it + */ + value = reinterpret_cast(attr); + xmlFree(attr); + return value; +} + +// KW std::string SaxReader::fullName(){ +// KW std::string value; +// KW xmlChar *name = xmlTextReaderName(m_reader); +// KW if(NULL == name) { +// KW LogError("Error in reading name."); +// KW Throw(Exception::ErrorReadingName); +// KW } +// KW value = reinterpret_cast(name); +// KW xmlFree(name); +// KW return value; +// KW } + +std::string SaxReader::name() +{ + std::string value; + xmlChar *name = xmlTextReaderName(m_reader); + if (NULL == name) { + LogError("Error in reading name."); + Throw(Exception::ErrorReadingName); + } + value = reinterpret_cast(name); + xmlFree(name); + size_t pos = value.find_last_of(":"); + if (pos != std::string::npos) { + value.erase(0, pos + 1); + } + return value; +} + +std::string SaxReader::namespaceURI() +{ + std::string value; + xmlChar *name = xmlTextReaderNamespaceUri(m_reader); + if (NULL != name) { + value = reinterpret_cast(name); + xmlFree(name); + } + return value; +} + +std::string SaxReader::value() +{ + std::string value; + /* + * get value of node + */ + xmlChar *text = xmlTextReaderValue(m_reader); + if (NULL == text) { + LogError("Error in reading value"); + Throw(Exception::ErrorReadingValue); + } + value = reinterpret_cast(text); + /* + * free text and return the val + */ + xmlFree(text); + return value; +} + +SaxReader::NodeType SaxReader::type() +{ + xmlReaderTypes type = + static_cast(xmlTextReaderNodeType(m_reader)); + switch (type) { + case XML_READER_TYPE_ELEMENT: + return NODE_BEGIN; + case XML_READER_TYPE_END_ELEMENT: + return NODE_END; + case XML_READER_TYPE_TEXT: + return NODE_TEXT; + case XML_READER_TYPE_NONE: + case XML_READER_TYPE_ATTRIBUTE: + case XML_READER_TYPE_CDATA: + case XML_READER_TYPE_ENTITY_REFERENCE: + case XML_READER_TYPE_ENTITY: + case XML_READER_TYPE_PROCESSING_INSTRUCTION: + case XML_READER_TYPE_COMMENT: + case XML_READER_TYPE_DOCUMENT: + case XML_READER_TYPE_DOCUMENT_TYPE: + case XML_READER_TYPE_DOCUMENT_FRAGMENT: + case XML_READER_TYPE_NOTATION: + case XML_READER_TYPE_WHITESPACE: + case XML_READER_TYPE_SIGNIFICANT_WHITESPACE: + case XML_READER_TYPE_END_ENTITY: + case XML_READER_TYPE_XML_DECLARATION: + default: + return NODE_UNSUPPORTED; + } +} + +void SaxReader::dumpNode(std::string &buffer) +{ + /* + * size of buffer + */ + int size; + /* + * pointer to buffer + */ + xmlBufferPtr buff = xmlBufferCreate(); + + xmlNodePtr node = xmlTextReaderExpand(m_reader); + + if (node == NULL) { + /* + * internal parser error + */ + xmlBufferFree(buff); + LogError("Parser Internal Error"); + Throw(Exception::ParserInternalError); + } + + /* + * get a size and fill in a buffer + */ + size = xmlNodeDump(buff, node->doc, node, 0, 0); + buffer.insert(0, reinterpret_cast(buff->content), size); + xmlBufferFree(buff); +} +} // namespace ValidationCore diff --git a/vcore/src/vcore/SaxReader.h b/vcore/src/vcore/SaxReader.h new file mode 100644 index 0000000..816405f --- /dev/null +++ b/vcore/src/vcore/SaxReader.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2011 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 SaxReader.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief Simple c++ interface for libxml2. + */ +#ifndef _SAXREADER_H_ +#define _SAXREADER_H_ + +#include +#include +#include + +namespace ValidationCore { +class SaxReader +{ + public: + SaxReader(); + ~SaxReader(); + + /* + * custom exceptions + */ + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, FileOpeningError) + DECLARE_EXCEPTION_TYPE(Base, FileNotValid) + DECLARE_EXCEPTION_TYPE(Base, ParserInternalError) + DECLARE_EXCEPTION_TYPE(Base, WrongToken) + DECLARE_EXCEPTION_TYPE(Base, ParserInternalErrorInReadingAttribute) + DECLARE_EXCEPTION_TYPE(Base, ParserInternalErrorInEmptyQuery) + DECLARE_EXCEPTION_TYPE(Base, ErrorReadingValue) + DECLARE_EXCEPTION_TYPE(Base, ErrorReadingName) + DECLARE_EXCEPTION_TYPE(Base, UnsupportedType) + }; + + enum NodeType + { + NODE_UNSUPPORTED, + NODE_BEGIN, + NODE_END, + NODE_TEXT + }; + + enum ThrowType + { + THROW_ENABLE = 0, + THROW_DISABLE + }; + + /* + * xml validation modes + */ + enum ValidationType + { + VALIDATION_DISABLE, + VALIDATION_XMLSCHEME, + VALIDATION_DTD + }; + + /* + * initializes parser + */ + void initialize(const std::string &filename, + bool defaultArgs = false, + ValidationType validation = VALIDATION_DISABLE, + const std::string &schema = std::string()); + /* + * deinitializes parser + */ + void deinitialize(); + + /** + * Move to next xml node. + */ + bool next(); + + /** + * Move to next xml node. If next node name is differ from token the exception will + * be thrown. + */ + void next(const std::string &token); + + /** + * Check if xml tag is empty. + */ + bool isEmpty(void); + + /** + * Read attribute tag. + */ + std::string attribute(const std::string &token, + ThrowType throwStatus = THROW_ENABLE); + + /** + * Read xml tag name with namespace. + */ + // KW std::string fullName(); + + /** + * Read xml tag name without namespace. + */ + std::string name(); + + /** + * Read xml tag namespace URI + */ + std::string namespaceURI(); + + /** + * Read xml tag value. + */ + std::string value(); + + /** + * Return information about node type. + */ + NodeType type(); + + /** + * Save all contonet of xml file which is between current tag and + * it's close tag into buffer. + */ + void dumpNode(std::string &buffer); + + private: + /* + * internal libxml text reader + */ + xmlTextReaderPtr m_reader; +}; +} + +#endif // _SAXREADER_H_ diff --git a/vcore/src/vcore/SignatureData.h b/vcore/src/vcore/SignatureData.h new file mode 100644 index 0000000..c0b7aad --- /dev/null +++ b/vcore/src/vcore/SignatureData.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2011 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 SignatureData.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief SignatureData is used to storage data parsed from digsig file. + */ +#ifndef _SIGNATUREDATA_H_ +#define _SIGNATUREDATA_H_ + +#include +#include +#include + +#include +#include +#include + +#include "Certificate.h" +#include "CertStoreType.h" +#include "ValidatorCommon.h" + +/* TODO this class should not depend from OCSP headers */ +#include "OCSPCertMgrUtil.h" + +namespace ValidationCore { +class SignatureData +{ + public: + + SignatureData() : + m_signatureNumber(-1), + m_certificateSorted(false) + { + } + + SignatureData(std::string fileName, + int fileNumber) : + m_signatureNumber(fileNumber), + m_fileName(fileName), + m_certificateSorted(false) + { + } + + virtual ~SignatureData() + { + } + typedef std::list IMEIList; + typedef std::list MEIDList; + + const ReferenceSet& getReferenceSet() const + { + return m_referenceSet; + } + + void setReference(const ReferenceSet &referenceSet) + { + m_referenceSet = referenceSet; + } + + CertificateList getCertList(void) const + { + return m_certList; + } + + void setSortedCertificateList(const CertificateList &list) + { + m_certList = list; + m_certificateSorted = true; + } + + bool isAuthorSignature(void) const + { + return m_signatureNumber == -1; + } + + std::string getSignatureFileName(void) const + { + return m_fileName; + } + + int getSignatureNumber() const + { + return m_signatureNumber; + } + + std::string getRoleURI() const + { + return m_roleURI; + } + + std::string getProfileURI() const + { + return m_profileURI; + } + + bool containObjectReference(const std::string &ref) const + { + std::string rName = "#"; + rName += ref; + return m_referenceSet.end() != m_referenceSet.find(rName); + } + + ObjectList getObjectList() const + { + return m_objectList; + } + + void setStorageType(const CertStoreId::Set &storeIdSet) + { + m_storeIdSet = storeIdSet; + } + + const CertStoreId::Set& getStorageType(void) const + { + return m_storeIdSet; + } + + const IMEIList& getIMEIList() const + { + return m_imeiList; + } + + const MEIDList& getMEIDList() const + { + return m_meidList; + } + + CertificatePtr getEndEntityCertificatePtr() const + { + if (m_certificateSorted) { + return m_certList.front(); + } + return CertificatePtr(); + } + + CertificatePtr getRootCaCertificatePtr() const + { + if (m_certificateSorted) { + return m_certList.back(); + } + return CertificatePtr(); + } + + friend class SignatureReader; + private: + ReferenceSet m_referenceSet; + CertificateList m_certList; + + //TargetRestriction + IMEIList m_imeiList; + MEIDList m_meidList; + + /* + * This number is taken from distributor signature file name. + * Author signature do not contain any number on the file name. + * Author signature should have signature number equal to -1. + */ + int m_signatureNumber; + std::string m_fileName; + std::string m_roleURI; + std::string m_profileURI; + std::string m_identifier; + ObjectList m_objectList; + CertStoreId::Set m_storeIdSet; + bool m_certificateSorted; +}; + +typedef std::set SignatureDataSet; +} + +#endif diff --git a/vcore/src/vcore/SignatureFinder.cpp b/vcore/src/vcore/SignatureFinder.cpp new file mode 100644 index 0000000..ed2a27f --- /dev/null +++ b/vcore/src/vcore/SignatureFinder.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011 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 SignatureFinder.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief Search for author-signature.xml and signatureN.xml files. + */ +#include +#include +#include + +#include + +#include "SignatureFinder.h" + +namespace ValidationCore { +static const char *SIGNATURE_AUTHOR = "author-signature.xml"; +static const char *REGEXP_DISTRIBUTOR_SIGNATURE = + "^(signature)([1-9][0-9]*)(\\.xml)"; + +SignatureFinder::SignatureFinder(const std::string& dir) : + m_dir(dir), + m_signatureRegexp(REGEXP_DISTRIBUTOR_SIGNATURE) +{ +} + +SignatureFinder::Result SignatureFinder::find(SignatureFileInfoSet &set) +{ + DIR *dp; + struct dirent *dirp; + + /* + * find a dir + */ + if ((dp = opendir(m_dir.c_str())) == NULL) { + LogError("Error opening directory:" << m_dir); + return ERROR_OPENING_DIR; + } + + for (errno = 0; (dirp = readdir(dp)) != NULL; errno = 0) { + /** + * check if it's author signature + */ + if (!strcmp(dirp->d_name, SIGNATURE_AUTHOR)) { + set.insert(SignatureFileInfo(std::string(dirp->d_name), -1)); + continue; + } + + std::string sig, num, xml; + if (m_signatureRegexp.FullMatch(dirp->d_name, &sig, &num, &xml)) { + std::istringstream stream(num); + int number; + stream >> number; + + if (stream.fail()) { + closedir(dp); + return ERROR_ISTREAM; + } + + set.insert(SignatureFileInfo(std::string(dirp->d_name), number)); + } + } + + if (errno != 0) { + LogError("Error in readdir"); + closedir(dp); + return ERROR_READING_DIR; + } + + closedir(dp); + return NO_ERROR; +} +} // namespace ValidationCore diff --git a/vcore/src/vcore/SignatureFinder.h b/vcore/src/vcore/SignatureFinder.h new file mode 100644 index 0000000..0e04213 --- /dev/null +++ b/vcore/src/vcore/SignatureFinder.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011 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 SignatureFinder.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief Search for author-signature.xml and signatureN.xml files. + */ +#ifndef _SIGNATUREFINDER_H_ +#define _SIGNATUREFINDER_H_ + +#include +#include + +#include + +#include "SignatureData.h" + +namespace ValidationCore { +class SignatureFileInfo +{ + public: + SignatureFileInfo(const std::string &fileName, + int num) : + m_fileName(fileName), + m_fileNumber(num) + { + } + + std::string getFileName() const + { + return m_fileName; + } + + int getFileNumber() const + { + return m_fileNumber; + } + + bool operator<(const SignatureFileInfo &second) const + { + return m_fileNumber < second.m_fileNumber; + } + private: + std::string m_fileName; + int m_fileNumber; +}; + +typedef std::set SignatureFileInfoSet; + +class SignatureFinder +{ + public: + enum Result + { + NO_ERROR, + ERROR_OPENING_DIR, + ERROR_READING_DIR, + ERROR_ISTREAM + }; + + SignatureFinder(const std::string& dir); + + Result find(SignatureFileInfoSet &set); + + private: + std::string m_dir; + pcrecpp::RE m_signatureRegexp; +}; +} // namespace ValidationCore + +#endif diff --git a/vcore/src/vcore/SignatureReader.cpp b/vcore/src/vcore/SignatureReader.cpp new file mode 100644 index 0000000..cf7540c --- /dev/null +++ b/vcore/src/vcore/SignatureReader.cpp @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2011 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 SignatureReader.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief SignatureReader is used to parse widget digital signature. + */ +#include "SignatureReader.h" + +#include "CertificateLoader.h" + +namespace ValidationCore { +static const std::string XML_NAMESPACE = + "http://www.w3.org/2000/09/xmldsig#"; +static const std::string XML_NAMESPACE_DIGITALSIG = + "http://wacapps.net/ns/digsig"; +static const std::string XML_OBJ_NS = + "http://www.w3.org/2009/xmldsig-properties"; + +// TAG TOKENS +static const std::string TOKEN_SIGNATURE = "Signature"; +static const std::string TOKEN_SIGNED_INFO = "SignedInfo"; +static const std::string TOKEN_CANONICALIZATION_METHOD = + "CanonicalizationMethod"; +static const std::string TOKEN_SIGNATURE_METHOD = "SignatureMethod"; +static const std::string TOKEN_REFERENCE = "Reference"; +static const std::string TOKEN_TRANSFORMS = "Transforms"; +static const std::string TOKEN_TRANSFORM = "Transform"; +static const std::string TOKEN_DIGEST_METHOD = "DigestMethod"; +static const std::string TOKEN_DIGEST_VALUE = "DigestValue"; +static const std::string TOKEN_SIGNATURE_VALUE = "SignatureValue"; +static const std::string TOKEN_KEY_INFO = "KeyInfo"; +static const std::string TOKEN_X509DATA = "X509Data"; +static const std::string TOKEN_X509CERTIFICATE = "X509Certificate"; +static const std::string TOKEN_KEY_VALUE = "KeyValue"; +static const std::string TOKEN_RSA_KEY_VALUE = "RSAKeyValue"; +static const std::string TOKEN_MODULUS_COMPONENT = "Modulus"; +static const std::string TOKEN_EXPONENT_COMPONENT = "Exponent"; +static const std::string TOKEN_ECKEY_VALUE = "ECKeyValue"; +static const std::string TOKEN_NAMED_CURVE = "NamedCurve"; +static const std::string TOKEN_PUBLIC_KEY = "PublicKey"; +static const std::string TOKEN_OBJECT = "Object"; +static const std::string TOKEN_SIGNATURE_PROPERTIES = "SignatureProperties"; +static const std::string TOKEN_SIGNATURE_PROPERTY = "SignatureProperty"; +static const std::string TOKEN_PROFILE = "Profile"; +static const std::string TOKEN_ROLE = "Role"; +static const std::string TOKEN_IDENTIFIER = "Identifier"; +static const std::string TOKEN_DSAKEYVALUE = "DSAKeyValue"; +static const std::string TOKEN_DSA_P_COMPONENT = "P"; +static const std::string TOKEN_DSA_Q_COMPONENT = "Q"; +static const std::string TOKEN_DSA_G_COMPONENT = "G"; +static const std::string TOKEN_DSA_Y_COMPONENT = "Y"; +static const std::string TOKEN_DSA_J_COMPONENT = "J"; +static const std::string TOKEN_DSA_SEED_COMPONENT = "Seed"; +static const std::string TOKEN_DSA_PGENCOUNTER_COMPONENT = "PgenCounter"; +static const std::string TOKEN_TARGET_RESTRICTION = "TargetRestriction"; + +// ATTRIBUTTE TOKENS + +static const std::string TOKEN_ALGORITHM = "Algorithm"; +static const std::string TOKEN_URI = "URI"; +static const std::string TOKEN_ID = "Id"; +static const std::string TOKEN_TARGET = "Target"; +static const std::string TOKEN_IMEI = "IMEI"; +static const std::string TOKEN_MEID = "MEID"; + +// ATTIRUBTE VALUES + +static const std::string TOKEN_ATTR_PROFILE = "profile"; +static const std::string TOKEN_ATTR_ROLE = "role"; +static const std::string TOKEN_ATTR_IDENTIFIER = "identifier"; + +// ALGORITHMS + +//static const std::string TOKEN_ALGORITHM_XML_EXC_CAN = +// "http://www.w3.org/2001/10/xml-exc-c14n#"; +//static const std::string TOKEN_ALGORITHM_RSA_SHA256 = +// "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; +//static const std::string TOKEN_ALGORITHM_DSA_SHA1 = +// "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; +//static const std::string TOKEN_ALGORITHM_ECDSA_SHA256 = +// "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"; +//static const std::string TOKEN_ALGORITHM_SHA1 = +// "http://www.w3.org/2000/09/xmldsig#sha1"; +//static const std::string TOKEN_ALGORITHM_SHA256 = +// "http://www.w3.org/2001/04/xmlenc#sha256"; +//static const std::string TOKEN_ALGORITHM_SHA384 = +// "http://www.w3.org/2001/04/xmldsig-more#sha384"; +//static const std::string TOKEN_ALGORITHM_SHA512 = +// "http://www.w3.org/2001/04/xmlenc#sha512"; + +SignatureReader::SignatureReader() : + m_signaturePropertiesCounter(0), + m_targetRestrictionObjectFound(false), + m_parserSchema(this) +{ + /** + * member func pointers map + */ + m_parserSchema.addBeginTagCallback(TOKEN_SIGNATURE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_SIGNED_INFO, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_CANONICALIZATION_METHOD, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_SIGNATURE_METHOD, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_REFERENCE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_TRANSFORMS, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_TRANSFORM, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_DIGEST_METHOD, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_DIGEST_VALUE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_SIGNATURE_VALUE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_KEY_INFO, + XML_NAMESPACE, + &SignatureReader::tokenKeyInfo); + m_parserSchema.addBeginTagCallback(TOKEN_X509DATA, + XML_NAMESPACE, + &SignatureReader::tokenX509Data); + m_parserSchema.addBeginTagCallback(TOKEN_X509CERTIFICATE, + XML_NAMESPACE, + &SignatureReader::tokenX509Certificate); + m_parserSchema.addBeginTagCallback(TOKEN_ECKEY_VALUE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_NAMED_CURVE, + XML_NAMESPACE, + &SignatureReader::tokenNamedCurve); + m_parserSchema.addBeginTagCallback(TOKEN_PUBLIC_KEY, + XML_NAMESPACE, + &SignatureReader::tokenPublicKey); + m_parserSchema.addBeginTagCallback(TOKEN_OBJECT, + XML_NAMESPACE, + &SignatureReader::tokenObject); + m_parserSchema.addBeginTagCallback( + TOKEN_SIGNATURE_PROPERTIES, + XML_NAMESPACE, + &SignatureReader:: + tokenSignatureProperties); + m_parserSchema.addBeginTagCallback(TOKEN_SIGNATURE_PROPERTY, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_PROFILE, + XML_OBJ_NS, + &SignatureReader::tokenProfile); + m_parserSchema.addBeginTagCallback(TOKEN_ROLE, + XML_OBJ_NS, + &SignatureReader::tokenRole); + m_parserSchema.addBeginTagCallback(TOKEN_IDENTIFIER, + XML_OBJ_NS, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_KEY_VALUE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_DSAKEYVALUE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_DSA_P_COMPONENT, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_DSA_Q_COMPONENT, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_DSA_G_COMPONENT, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_DSA_Y_COMPONENT, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_DSA_J_COMPONENT, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_DSA_SEED_COMPONENT, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_DSA_PGENCOUNTER_COMPONENT, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_RSA_KEY_VALUE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_MODULUS_COMPONENT, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_EXPONENT_COMPONENT, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addBeginTagCallback(TOKEN_TARGET_RESTRICTION, + XML_NAMESPACE_DIGITALSIG, + &SignatureReader::tokenTargetRestriction); + + m_parserSchema.addEndTagCallback(TOKEN_SIGNATURE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_SIGNED_INFO, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_CANONICALIZATION_METHOD, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_SIGNATURE_METHOD, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_REFERENCE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_TRANSFORMS, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_TRANSFORM, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_DIGEST_METHOD, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_DIGEST_VALUE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_SIGNATURE_VALUE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_KEY_INFO, + XML_NAMESPACE, + &SignatureReader::tokenEndKeyInfo); + m_parserSchema.addEndTagCallback(TOKEN_X509DATA, + XML_NAMESPACE, + &SignatureReader::tokenEndX509Data); + m_parserSchema.addEndTagCallback(TOKEN_X509CERTIFICATE, + XML_NAMESPACE, + &SignatureReader::tokenEndX509Certificate); + m_parserSchema.addEndTagCallback(TOKEN_ECKEY_VALUE, + XML_NAMESPACE, + &SignatureReader::tokenEndECKeyValue); + m_parserSchema.addEndTagCallback(TOKEN_PUBLIC_KEY, + XML_NAMESPACE, + &SignatureReader::tokenEndPublicKey); + m_parserSchema.addEndTagCallback(TOKEN_OBJECT, + XML_NAMESPACE, + &SignatureReader::tokenEndObject); + m_parserSchema.addEndTagCallback(TOKEN_SIGNATURE_PROPERTIES, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_SIGNATURE_PROPERTY, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_PROFILE, + XML_OBJ_NS, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_ROLE, + XML_OBJ_NS, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_IDENTIFIER, + XML_OBJ_NS, + &SignatureReader::tokenEndIdentifier); + m_parserSchema.addEndTagCallback(TOKEN_KEY_VALUE, + XML_NAMESPACE, + &SignatureReader::blankFunction); + m_parserSchema.addEndTagCallback(TOKEN_DSAKEYVALUE, + XML_NAMESPACE, + &SignatureReader::tokenEndDSAKeyValue); + m_parserSchema.addEndTagCallback(TOKEN_DSA_P_COMPONENT, + XML_NAMESPACE, + &SignatureReader::tokenEndDSAPComponent); + m_parserSchema.addEndTagCallback(TOKEN_DSA_Q_COMPONENT, + XML_NAMESPACE, + &SignatureReader::tokenEndDSAQComponent); + m_parserSchema.addEndTagCallback(TOKEN_DSA_G_COMPONENT, + XML_NAMESPACE, + &SignatureReader::tokenEndDSAGComponent); + m_parserSchema.addEndTagCallback(TOKEN_DSA_Y_COMPONENT, + XML_NAMESPACE, + &SignatureReader::tokenEndDSAYComponent); + m_parserSchema.addEndTagCallback(TOKEN_DSA_J_COMPONENT, + XML_NAMESPACE, + &SignatureReader::tokenEndDSAJComponent); + m_parserSchema.addEndTagCallback(TOKEN_DSA_SEED_COMPONENT, + XML_NAMESPACE, + &SignatureReader::tokenEndDSASeedComponent); + m_parserSchema.addEndTagCallback( + TOKEN_DSA_PGENCOUNTER_COMPONENT, + XML_NAMESPACE, + &SignatureReader:: + tokenEndDSAPGenCounterComponent); + m_parserSchema.addEndTagCallback(TOKEN_RSA_KEY_VALUE, + XML_NAMESPACE, + &SignatureReader::tokenEndRSAKeyValue); + m_parserSchema.addEndTagCallback(TOKEN_MODULUS_COMPONENT, + XML_NAMESPACE, + &SignatureReader::tokenEndKeyModulus); + m_parserSchema.addEndTagCallback(TOKEN_EXPONENT_COMPONENT, + XML_NAMESPACE, + &SignatureReader::tokenEndKeyExponent); + m_parserSchema.addEndTagCallback(TOKEN_TARGET_RESTRICTION, + XML_NAMESPACE, + &SignatureReader::blankFunction); +} + +void SignatureReader::tokenKeyInfo(SignatureData &signatureData) +{ + (void)signatureData; +} +void SignatureReader::tokenX509Data(SignatureData &signatureData) +{ + (void)signatureData; +} +void SignatureReader::tokenX509Certificate(SignatureData &signatureData) +{ + (void)signatureData; +} +void SignatureReader::tokenPublicKey(SignatureData &signatureData) +{ + (void)signatureData; +} + +void SignatureReader::tokenNamedCurve(SignatureData &signatureData) +{ + (void)signatureData; + m_nameCurveURI = m_parserSchema.getReader().attribute(TOKEN_URI); +} + +void SignatureReader::tokenTargetRestriction(SignatureData &signatureData) +{ + std::string IMEI = m_parserSchema.getReader().attribute( + TOKEN_IMEI, + SaxReader:: + THROW_DISABLE); + std::string MEID = m_parserSchema.getReader().attribute( + TOKEN_MEID, + SaxReader:: + THROW_DISABLE); + + //less verbose way to say (IMEI && MEID) || (!IMEI && !MEID) + if (IMEI.empty() == MEID.empty()) { + //WAC 2.0 WR-4650 point 4 + ThrowMsg(Exception::TargetRestrictionException, + "TargetRestriction should contain exactly one attribute."); + return; + } + + if (!IMEI.empty()) { + signatureData.m_imeiList.push_back(IMEI); + } + if (!MEID.empty()) { + signatureData.m_meidList.push_back(MEID); + } +} + +void SignatureReader::tokenEndKeyInfo(SignatureData &signatureData) +{ + (void)signatureData; +} + +void SignatureReader::tokenEndX509Data(SignatureData &signatureData) +{ + (void)signatureData; +} + +void SignatureReader::tokenEndX509Certificate(SignatureData &signatureData) +{ + CertificateLoader loader; + if (CertificateLoader::NO_ERROR != + loader.loadCertificateFromRawData(m_parserSchema.getText())) { + LogWarning("Certificate could not be loaded!"); + ThrowMsg(ParserSchemaException::CertificateLoaderError, + "Certificate could not be loaded."); + } + signatureData.m_certList.push_back(loader.getCertificatePtr()); +} +// KW void SignatureReader::tokenEndKeyName(SignatureData &signatureData){ +// KW CertificateLoader loader; +// KW if(CertificateLoader::NO_ERROR != loader.loadCertificateBasedOnSubjectName(m_parserSchema.getText())){ +// KW LogError("Certificate could not be loaded!"); +// KW ThrowMsg(ParserSchemaException::CertificateLoaderError, "Certificate could not be loaded."); +// KW } +// KW signatureData.m_certList.push_back(loader); +// KW } + +void SignatureReader::tokenEndRSAKeyValue(SignatureData &signatureData) +{ + CertificateLoader loader; + if (CertificateLoader::NO_ERROR != + loader.loadCertificateBasedOnExponentAndModulus(m_modulus, + m_exponent)) { + LogWarning("Certificate could not be loaded!"); + ThrowMsg(ParserSchemaException::CertificateLoaderError, + "Certificate could not be loaded."); + } + signatureData.m_certList.push_back(loader.getCertificatePtr()); +} + +void SignatureReader::tokenEndKeyModulus(SignatureData &signatureData) +{ + (void)signatureData; + m_modulus = m_parserSchema.getText(); +} + +void SignatureReader::tokenEndKeyExponent(SignatureData &signatureData) +{ + (void)signatureData; + m_exponent = m_parserSchema.getText(); +} + +void SignatureReader::tokenEndPublicKey(SignatureData &signatureData) +{ + (void)signatureData; + m_publicKey = m_parserSchema.getText(); +} + +void SignatureReader::tokenEndECKeyValue(SignatureData &signatureData) +{ + CertificateLoader loader; + if (CertificateLoader::NO_ERROR != + loader.loadCertificateWithECKEY(m_nameCurveURI, m_publicKey)) { + ThrowMsg(ParserSchemaException::CertificateLoaderError, + "Certificate could not be loaded."); + } + signatureData.m_certList.push_back(loader.getCertificatePtr()); +} + +void SignatureReader::tokenEndObject(SignatureData &signatureData) +{ + m_signaturePropertiesCounter = 0; + + if (((!signatureData.m_imeiList.empty()) || + (!signatureData.m_meidList.empty())) && + m_targetRestrictionObjectFound) { + //WAC 2.0 WR-4650 point 1 + ThrowMsg( + Exception::TargetRestrictionException, + "TargetRestriction should contain exactly one ds:Object containing zero or more wac:TargetRestriction children."); + return; + } + if ((!signatureData.m_imeiList.empty()) || + (!signatureData.m_meidList.empty())) { + m_targetRestrictionObjectFound = true; + } +} +void SignatureReader::tokenEndDSAPComponent(SignatureData& signatureData) +{ + (void)signatureData; + m_dsaKeyPComponent = m_parserSchema.getText(); +} + +void SignatureReader::tokenEndDSAQComponent(SignatureData& signatureData) +{ + (void)signatureData; + m_dsaKeyQComponent = m_parserSchema.getText(); +} + +void SignatureReader::tokenEndDSAGComponent(SignatureData& signatureData) +{ + (void)signatureData; + m_dsaKeyGComponent = m_parserSchema.getText(); +} + +void SignatureReader::tokenEndDSAYComponent(SignatureData& signatureData) +{ + (void)signatureData; + m_dsaKeyYComponent = m_parserSchema.getText(); +} + +void SignatureReader::tokenEndDSAJComponent(SignatureData& signatureData) +{ + (void)signatureData; + m_dsaKeyJComponent = m_parserSchema.getText(); +} + +void SignatureReader::tokenEndDSASeedComponent(SignatureData& signatureData) +{ + (void)signatureData; + m_dsaKeySeedComponent = m_parserSchema.getText(); +} + +void SignatureReader::tokenEndDSAPGenCounterComponent( + SignatureData& signatureData) +{ + (void)signatureData; + m_dsaKeyPGenCounter = m_parserSchema.getText(); +} + +void SignatureReader::tokenEndDSAKeyValue(SignatureData& signatureData) +{ + CertificateLoader loader; + + if (CertificateLoader::NO_ERROR != + loader.loadCertificateBasedOnDSAComponents(m_dsaKeyPComponent, + m_dsaKeyQComponent, + m_dsaKeyGComponent, + m_dsaKeyYComponent, + m_dsaKeyJComponent, + m_dsaKeySeedComponent, + m_dsaKeyPGenCounter)) { + LogWarning("Certificate could not be loaded."); + ThrowMsg(ParserSchemaException::CertificateLoaderError, + "Certificate could not be loaded."); + } + signatureData.m_certList.push_back(loader.getCertificatePtr()); +} + +void SignatureReader::tokenRole(SignatureData &signatureData) +{ + if (!signatureData.m_roleURI.empty()) { + LogWarning("Multiple definition of Role is not allowed."); + ThrowMsg(ParserSchemaException::UnsupportedValue, + "Multiple definition of Role is not allowed."); + } + signatureData.m_roleURI = m_parserSchema.getReader().attribute(TOKEN_URI); +} + +void SignatureReader::tokenProfile(SignatureData &signatureData) +{ + if (!signatureData.m_profileURI.empty()) { + LogWarning("Multiple definition of Profile is not allowed."); + ThrowMsg(ParserSchemaException::UnsupportedValue, + "Multiple definition of Profile is not allowed."); + } + signatureData.m_profileURI = m_parserSchema.getReader().attribute(TOKEN_URI); +} + +void SignatureReader::tokenEndIdentifier(SignatureData &signatureData) +{ + if (!signatureData.m_identifier.empty()) { + LogWarning("Multiple definition of Identifier is not allowed."); + ThrowMsg(ParserSchemaException::UnsupportedValue, + "Multiple definition of Identifier is not allowed."); + } + signatureData.m_identifier = m_parserSchema.getText(); +} + +void SignatureReader::tokenObject(SignatureData &signatureData) +{ + std::string id = m_parserSchema.getReader().attribute(TOKEN_ID); + + if (id.empty()) { + LogWarning("Unsupported value of Attribute Id in Object tag."); + ThrowMsg(ParserSchemaException::UnsupportedValue, + "Unsupported value of Attribute Id in Object tag."); + } + + signatureData.m_objectList.push_back(id); +} + +void SignatureReader::tokenSignatureProperties(SignatureData &signatureData) +{ + (void)signatureData; + if (++m_signaturePropertiesCounter > 1) { + LogWarning("Only one SignatureProperties tag is allowed in Object"); + ThrowMsg(ParserSchemaException::UnsupportedValue, + "Only one SignatureProperties tag is allowed in Object"); + } +} +} // namespace ValidationCore diff --git a/vcore/src/vcore/SignatureReader.h b/vcore/src/vcore/SignatureReader.h new file mode 100644 index 0000000..e6368fc --- /dev/null +++ b/vcore/src/vcore/SignatureReader.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2011 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 SignatureReader.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief SignatureReader is used to parse widget digital signature. + */ +#ifndef _SIGNATUREREADER_H_ +#define _SIGNATUREREADER_H_ + +#include +#include + +#include "SignatureData.h" +#include "ParserSchema.h" + +namespace ValidationCore { +class SignatureReader +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, TargetRestrictionException) + }; + + SignatureReader(); + + void initialize(SignatureData &data, + const std::string &xmlscheme) + { + m_parserSchema.initialize( + data.getSignatureFileName(), true, SaxReader::VALIDATION_XMLSCHEME, + xmlscheme); + } + + void read(SignatureData &data) + { + m_parserSchema.read(data); + } + + private: + void blankFunction(SignatureData &) + { + } + + void tokenKeyInfo(SignatureData &signatureData); + void tokenKeyModulus(SignatureData &signatureData); + void tokenKeyExponent(SignatureData &signatureData); + void tokenX509Data(SignatureData &signatureData); + void tokenX509Certificate(SignatureData &signatureData); + void tokenPublicKey(SignatureData &signatureData); + void tokenNamedCurve(SignatureData &signatureData); + void tokenRole(SignatureData &signatureData); + void tokenProfile(SignatureData &signatureData); + void tokenObject(SignatureData &signatureData); + void tokenSignatureProperties(SignatureData &signatureData); + void tokenTargetRestriction(SignatureData &signatureData); + + void tokenEndKeyInfo(SignatureData &signatureData); + // KW void tokenEndKeyName(SignatureData &signatureData); + void tokenEndRSAKeyValue(SignatureData &signatureData); + void tokenEndKeyModulus(SignatureData &signatureData); + void tokenEndKeyExponent(SignatureData &signatureData); + void tokenEndX509Data(SignatureData &signatureData); + void tokenEndX509Certificate(SignatureData &signatureData); + void tokenEndPublicKey(SignatureData &signatureData); + void tokenEndECKeyValue(SignatureData &signatureData); + void tokenEndIdentifier(SignatureData &signatureData); + void tokenEndObject(SignatureData &signatureData); + + // DSA key components + void tokenEndDSAPComponent(SignatureData& signatureData); + void tokenEndDSAQComponent(SignatureData& signatureData); + void tokenEndDSAGComponent(SignatureData& signatureData); + void tokenEndDSAYComponent(SignatureData& signatureData); + void tokenEndDSAJComponent(SignatureData& signatureData); + + void tokenEndDSAKeyValue(SignatureData& signatureData); + + void tokenEndDSASeedComponent(SignatureData& signatureData); + void tokenEndDSAPGenCounterComponent(SignatureData& signatureData); + + // temporary values required due reference parsing process + // optional parameters for dsa + std::string m_dsaKeyPComponent; + std::string m_dsaKeyQComponent; + std::string m_dsaKeyGComponent; + std::string m_dsaKeyYComponent; + std::string m_dsaKeyJComponent; + std::string m_dsaKeySeedComponent; + std::string m_dsaKeyPGenCounter; + // temporary values of ecdsa key + std::string m_publicKey; + std::string m_nameCurveURI; + std::string m_modulus; + std::string m_exponent; + + // temporary values required due Object parsing + int m_signaturePropertiesCounter; + bool m_targetRestrictionObjectFound; + + ParserSchema m_parserSchema; +}; +} + +#endif diff --git a/vcore/src/vcore/SignatureValidator.cpp b/vcore/src/vcore/SignatureValidator.cpp new file mode 100644 index 0000000..e965ecc --- /dev/null +++ b/vcore/src/vcore/SignatureValidator.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2011 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. + */ +#include +#include +#include + +#include + +#include "CertificateVerifier.h" +#include "OCSPCertMgrUtil.h" +#include "Certificate.h" +#include "ReferenceValidator.h" +#include "SignatureValidator.h" +#include "SSLContainers.h" +#include "ValidatorCommon.h" +#include "ValidatorFactories.h" +#include "XmlsecAdapter.h" + +namespace { +const time_t TIMET_DAY = 60 * 60 * 24; + +const std::string TOKEN_ROLE_AUTHOR_URI = + "http://www.w3.org/ns/widgets-digsig#role-author"; +const std::string TOKEN_ROLE_DISTRIBUTOR_URI = + "http://www.w3.org/ns/widgets-digsig#role-distributor"; +const std::string TOKEN_PROFILE_URI = + "http://www.w3.org/ns/widgets-digsig#profile"; +} // namespace anonymouse + +namespace ValidationCore { + +SignatureValidator::SignatureValidator(bool ocspEnable, + bool crlEnable, + bool complianceMode) : + m_ocspEnable(ocspEnable), + m_crlEnable(crlEnable), + m_complianceModeEnabled(complianceMode) +{ +} + +SignatureValidator::~SignatureValidator() +{ +} + +bool SignatureValidator::checkRoleURI(const SignatureData &data) +{ + std::string roleURI = data.getRoleURI(); + + if (roleURI.empty()) { + LogWarning("URI attribute in Role tag couldn't be empty."); + return false; + } + + if (roleURI != TOKEN_ROLE_AUTHOR_URI && data.isAuthorSignature()) { + LogWarning("URI attribute in Role tag does not " + "match with signature filename."); + return false; + } + + if (roleURI != TOKEN_ROLE_DISTRIBUTOR_URI && !data.isAuthorSignature()) { + LogWarning("URI attribute in Role tag does not " + "match with signature filename."); + return false; + } + return true; +} + +bool SignatureValidator::checkProfileURI(const SignatureData &data) +{ + if (TOKEN_PROFILE_URI != data.getProfileURI()) { + LogWarning( + "Profile tag contains unsupported value in URI attribute(" << + data.getProfileURI() << ")."); + return false; + } + return true; +} + +bool SignatureValidator::checkObjectReferences(const SignatureData &data) +{ + ObjectList objectList = data.getObjectList(); + ObjectList::const_iterator iter; + for (iter = objectList.begin(); iter != objectList.end(); ++iter) { + if (!data.containObjectReference(*iter)) { + LogWarning("Signature does not contain reference for object " << + *iter); + return false; + } + } + return true; +} + +SignatureValidator::Result SignatureValidator::check( + SignatureData &data, + const std::string &widgetContentPath) +{ + bool disregard = false; + + if (!checkRoleURI(data)) { + return SIGNATURE_INVALID; + } + + if (!checkProfileURI(data)) { + return SIGNATURE_INVALID; + } + + // CertificateList sortedCertificateList = data.getCertList(); + + CertificateCollection collection; + collection.load(data.getCertList()); + + // First step - sort certificate + if (!collection.sort()) { + LogWarning("Certificates do not form valid chain."); + return SIGNATURE_INVALID; + } + + // Check for error + if (collection.empty()) { + LogWarning("Certificate list in signature is empty."); + return SIGNATURE_INVALID; + } + + CertificateList sortedCertificateList = collection.getChain(); + + // TODO move it to CertificateCollection + // Add root CA and CA certificates (if chain is incomplete) + sortedCertificateList = + OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList); + + CertificatePtr root = sortedCertificateList.back(); + + // Is Root CA certificate trusted? + CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root); + + // WAC chapter 3.2.1 - verified definition + if (data.isAuthorSignature()) { + if (!storeIdSet.contains(CertStoreId::WAC_PUBLISHER)) { + LogWarning("Author signature has got unrecognized Root CA " + "certificate. Signature will be disregarded."); + disregard = true; + } + LogDebug("Root CA for author signature is correct."); + } else { + if (!storeIdSet.contains(CertStoreId::DEVELOPER) && + !storeIdSet.contains(CertStoreId::WAC_ROOT) && + !storeIdSet.contains(CertStoreId::WAC_MEMBER)) + { + LogWarning("Distiributor signature has got unrecognized Root CA " + "certificate. Signature will be disregarded."); + disregard = true; + } + LogDebug("Root CA for distributor signature is correct."); + } + + data.setStorageType(storeIdSet); + data.setSortedCertificateList(sortedCertificateList); + + // We add only Root CA certificate because WAC ensure that the rest + // of certificates are present in signature files ;-) + XmlSec::XmlSecContext context; + context.signatureFile = data.getSignatureFileName(); + context.certificatePtr = root; + + // Now we should have full certificate chain. + // If the end certificate is not ROOT CA we should disregard signature + // but still signature must be valid... Aaaaaa it's so stupid... + if (!(root->isSignedBy(root))) { + LogWarning("Root CA certificate not found. Chain is incomplete."); + context.allowBrokenChain = true; + } + + // WAC 2.0 SP-2066 The wrt must not block widget installation + // due to expiration of the author certificate. + time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter(); + bool expired = notAfter < time(NULL); + if (data.isAuthorSignature() && expired) { + context.validationTime = notAfter - TIMET_DAY; + } + // end + + if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) { + LogWarning("Installation break - invalid package!"); + return SIGNATURE_INVALID; + } + + data.setReference(context.referenceSet); + + if (!checkObjectReferences(data)) { + return SIGNATURE_INVALID; + } + + ReferenceValidator fileValidator(widgetContentPath); + if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) { + LogWarning("Invalid package - file references broken"); + return SIGNATURE_INVALID; + } + + // It is good time to do OCSP check + // ocspCheck will throw an exception on any error. + // TODO Probably we should catch this exception and add + // some information to SignatureData. + if (!m_complianceModeEnabled && !data.isAuthorSignature()) { + CertificateCollection coll; + coll.load(sortedCertificateList); + + if (!coll.sort()) { + LogDebug("Collection does not contain chain!"); + return SIGNATURE_INVALID; + } + + CertificateVerifier verificator(m_ocspEnable, m_crlEnable); + VerificationStatus result = verificator.check(coll); + + if (result == VERIFICATION_STATUS_REVOKED) { + return SIGNATURE_REVOKED; + } + + if (result == VERIFICATION_STATUS_UNKNOWN || + result == VERIFICATION_STATUS_ERROR) + { + disregard = true; + } + } + + if (disregard) { + LogWarning("Signature is disregard."); + return SIGNATURE_DISREGARD; + } + return SIGNATURE_VERIFIED; +} + +std::string SignatureValidator::FingerprintToColonHex( + const Certificate::Fingerprint &fingerprint) +{ + std::string outString; + + char buff[8]; + + for (size_t i = 0; i < fingerprint.size(); ++i) { + snprintf(buff, + sizeof(buff), + "%02X:", + static_cast(fingerprint[i])); + outString += buff; + } + + // remove trailing ":" + outString.erase(outString.end() - 1); + return outString; +} +} // namespace ValidationCore diff --git a/vcore/src/vcore/SignatureValidator.h b/vcore/src/vcore/SignatureValidator.h new file mode 100644 index 0000000..aa381cb --- /dev/null +++ b/vcore/src/vcore/SignatureValidator.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 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. + */ +#ifndef _SIGNATUREVALIDATOR_H_ +#define _SIGNATUREVALIDATOR_H_ + +#include + +#include "Certificate.h" +#include "OCSPCertMgrUtil.h" +#include "SignatureData.h" + +#include "ValidatorCommon.h" +#include "VerificationStatus.h" + +namespace ValidationCore { +// Todo nocopyable +class SignatureValidator +{ + public: + enum Result + { + SIGNATURE_VALID, + SIGNATURE_INVALID, + SIGNATURE_VERIFIED, + SIGNATURE_DISREGARD, // no ocsp response or ocsp return unknown status + SIGNATURE_REVOKED + }; + + /** + * Validation of the signature. + * If falidation succeed SignatureData will contains: + * list of validated references + * set selfSigned value + * root ca certificate + * end entity certificate + */ + Result check(SignatureData &data, + const std::string &widgetContentPath); + + static std::string FingerprintToColonHex( + const Certificate::Fingerprint &fingerprint); + + explicit SignatureValidator(bool ocspEnable, + bool crlEnable, + bool complianceMode); + virtual ~SignatureValidator(); + + private: + bool checkRoleURI(const SignatureData &data); + bool checkProfileURI(const SignatureData &data); + bool checkObjectReferences(const SignatureData &data); + + bool m_ocspEnable; + bool m_crlEnable; + bool m_complianceModeEnabled; +}; + +} // namespace ValidationCore + +#endif // _SIGNATUREVALIDATOR_H_ diff --git a/vcore/src/vcore/SoupMessageSendAsync.cpp b/vcore/src/vcore/SoupMessageSendAsync.cpp new file mode 100644 index 0000000..d8bb132 --- /dev/null +++ b/vcore/src/vcore/SoupMessageSendAsync.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2011 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. + */ diff --git a/vcore/src/vcore/SoupMessageSendAsync.h b/vcore/src/vcore/SoupMessageSendAsync.h new file mode 100644 index 0000000..c6900e2 --- /dev/null +++ b/vcore/src/vcore/SoupMessageSendAsync.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 0.1 + * @file SoupMessageSendAsync.h + * @brief Routines for certificate validation over OCSP + */ +#ifndef _SRC_VALIDATION_CORE_SOUP_MESSAGE_SEND_ASYNC_H_ +#define _SRC_VALIDATION_CORE_SOUP_MESSAGE_SEND_ASYNC_H_ + +#include +#include + +#include + +#include + +#include "SoupMessageSendBase.h" + +namespace SoupWrapper { + +class SoupMessageSendAsync + : public SoupMessageSendBase + , public DPL::Event::ICDelegateSupport +{ + typedef DPL::Event::ICDelegate SoupDelegate; + public: + void sendAsync() { + Assert(m_status == STATUS_IDLE); + Assert(!m_soupSession); + Assert(!m_soupMessage); + + m_status = STATUS_SEND_ASYNC; + m_tryLeft = m_tryCount; + m_mainContext = g_main_context_new(); + + if (!m_mainContext){ + m_status = STATUS_IDLE; + + // call the delegate to outside with error! + return; + } + + m_soupSession = soup_session_async_new_with_options( + SOUP_SESSION_ASYNC_CONTEXT, + m_mainContext, + SOUP_SESSION_TIMEOUT, + m_timeout, + NULL); + + if (!m_soupSession){ + m_status = STATUS_IDLE; + g_object_unref(m_mainContext); + m_mainContext = 0; + + // call the deletage to outside with error! + return; + } + + m_soupMessage = createRequest(); + + if (!m_soupMessage){ + m_status = STATUS_IDLE; + g_object_unref(m_soupSession); + m_soupSession = 0; + g_object_unref(m_mainContext); + m_mainContext = 0; + + // call the delegate to outsize with error! + return; + } + + sendAsyncIterationStart(); + } + + protected: + + struct SoupDelegateOpaque { + SoupDelegate dlg; + }; + + void sendAsyncIterationStart(){ + // ICDelegate could be called only once. + // We can set user data only once. + // We need nasty hack because we will call ICDelegate m_tryCount times. + SoupDelegateOpaque *opaq = new SoupDelegateOpaque; + opaq->dlg = makeICDelegate(&SoupMessageSendAsync::requestReceiver); + + soup_session_queue_message(m_soupSession, + m_soupMessage, + soupSessionCallback, + reinterpret_cast(opaq)); + } + + void sendAsyncIteration(SoupDelegateOpaque *opaq){ + // Replace used ICDelegate with new one without changing + // userdata ;-) + opaq->dlg = makeICDelegate(&SoupMessageSendAsync::requestReceiver); + soup_session_requeue_message(m_soupSession, + m_soupMessage); + } + + void requestReceiver(SoupSession *session, SoupMessage *msg, void *opaque){ + // We are in thread which called sendAsync function. + Assert(session == m_soupSession); + Assert(msg == m_soupMessage); + Assert(opaque != 0); + Assert(m_status == STATUS_SEND_ASYNC); + + m_tryLeft--; + + if (msg->status_code == SOUP_STATUS_OK) { + m_responseBuffer.resize(msg->response_body->length); + memcpy(&m_responseBuffer[0], + msg->response_body->data, + msg->response_body->length); + // We are done. + m_status = STATUS_IDLE; + delete static_cast(opaque); + + // call the delegate to outside! + return; + } + + // Error protocol // + if (m_tryLeft <= 0) { + m_status = STATUS_IDLE; + delete static_cast(opaque); + + // call the delegate to outside with error! + return; + } + + // create delegate and send the request once again. + sendAsyncIteration(reinterpret_cast(opaque)); + } + + static void soupSessionCallback(SoupSession *session, + SoupMessage *msg, + gpointer userdata) + { + // We are in main thread. We need to switch context. + // This delegate can switch context to dpl thread or main thread. + SoupDelegateOpaque *opaque; + opaque = reinterpret_cast(userdata); + opaque->dlg(session, msg, userdata); + } + + int m_tryLeft; + + GMainContext *m_mainContext; + SoupSession *m_soupSession; + SoupMessage *m_soupMessage; +}; + +} // namespace ValidationCore + +#endif diff --git a/vcore/src/vcore/SoupMessageSendBase.cpp b/vcore/src/vcore/SoupMessageSendBase.cpp new file mode 100644 index 0000000..3518a71 --- /dev/null +++ b/vcore/src/vcore/SoupMessageSendBase.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 0.1 + * @file SoupMessageSendBase.cpp + * @brief Simple wrapper for soup. + */ +#include "SoupMessageSendBase.h" + +#include +#include +#include + +namespace SoupWrapper { + +SoupMessageSendBase::SoupMessageSendBase() + : m_status(STATUS_IDLE) + , m_timeout(30) + , m_tryCount(5) +{} + +SoupMessageSendBase::~SoupMessageSendBase(){ + Assert(m_status == STATUS_IDLE); +} + +void SoupMessageSendBase::setHeader(const std::string &property, const std::string &value){ + Assert(m_status == STATUS_IDLE); + m_headerMap[property] = value; +} + +void SoupMessageSendBase::setHost(const std::string &host){ + Assert(m_status == STATUS_IDLE); + m_host = host; +} + +void SoupMessageSendBase::setRequest(const std::string &contentType, const MessageBuffer &message){ + Assert(m_status == STATUS_IDLE); + m_requestType = contentType; + m_requestBuffer = message; +} + +SoupMessageSendBase::MessageBuffer SoupMessageSendBase::getResponse() const { + Assert(m_status == STATUS_IDLE); + return m_responseBuffer; +} + +void SoupMessageSendBase::setTimeout(int seconds) { + Assert(m_status == STATUS_IDLE); + Assert(seconds >= 0); + m_timeout = seconds; +} + +void SoupMessageSendBase::setRetry(int retry) { + Assert(m_status == STATUS_IDLE); + Assert(retry >= 0); + m_tryCount = retry + 1; +} + + +SoupMessage* SoupMessageSendBase::createRequest(){ + SoupMessage *message; + + LogInfo("Soup message will be send to: " << m_host.c_str()); + + if (!m_requestBuffer.empty()) { + message = soup_message_new("POST", m_host.c_str()); + } else { + message = soup_message_new("GET", m_host.c_str()); + } + + if (!message) { + LogError("Error creating request!"); + return 0; + } + + FOREACH(it, m_headerMap){ + soup_message_headers_append(message->request_headers, + it->first.c_str(), + it->second.c_str()); + } + + if (!m_requestBuffer.empty()) { + soup_message_set_http_version(message, SOUP_HTTP_1_0); + soup_message_set_request(message, + m_requestType.c_str(), + SOUP_MEMORY_COPY, + &m_requestBuffer[0], + m_requestBuffer.size()); + } +// soup_message_set_flags(message, SOUP_MESSAGE_NO_REDIRECT); + return message; +} + +} // namespace ValidationCore diff --git a/vcore/src/vcore/SoupMessageSendBase.h b/vcore/src/vcore/SoupMessageSendBase.h new file mode 100644 index 0000000..aaa5fb4 --- /dev/null +++ b/vcore/src/vcore/SoupMessageSendBase.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 0.1 + * @file SoupMessageSendBase.h + * @brief Simple wrapper for soup. + */ +#ifndef _SRC_VALIDATION_CORE_SOUP_MESSAGE_SEND_BASE_H_ +#define _SRC_VALIDATION_CORE_SOUP_MESSAGE_SEND_BASE_H_ + +#include +#include +#include + +#include + +namespace SoupWrapper { + +class SoupMessageSendBase { + public: + + typedef std::vector MessageBuffer; + typedef std::map HeaderMap; + + enum RequestStatus { + REQUEST_STATUS_OK, + REQUEST_STATUS_CONNECTION_ERROR + }; + + SoupMessageSendBase(); + + virtual ~SoupMessageSendBase(); + + /** + * Add specific information to request header. + * + * @param[in] property property name (for example "Host") + * @param[in] value property value (for example "onet.pl:80") + */ + void setHeader(const std::string &property, + const std::string &value); + + /** + * Set request destination. + * + * @param[in] host - full path to source (http://onet.pl/index.html) + */ + void setHost(const std::string &host); + + /** + * Set body of request. + * + * @param[in] contentType (for example: "application/ocsp-request") + * @param[in] message body of reqeust + */ + void setRequest(const std::string &contentType, + const MessageBuffer &message); + + /** + * Set network timeout. Default is 30 seconds. + * + * @param[in] seconds timeout in seconds + */ + void setTimeout(int seconds); + + /** + * How many erros soup will accept before he will terminate connection. + * Default is 5. + * + * @param[in] retry number + */ + void setRetry(int retry); + + /** + * Get response from serwer. + */ + MessageBuffer getResponse() const; + + protected: + + SoupMessage* createRequest(); + + enum Status { + STATUS_IDLE, + STATUS_SEND_SYNC, + STATUS_SEND_ASYNC + }; + + Status m_status; + + int m_timeout; + int m_tryCount; + + std::string m_host; + std::string m_requestType; + MessageBuffer m_requestBuffer; + MessageBuffer m_responseBuffer; + HeaderMap m_headerMap; +}; + +} // namespace ValidationCore + +#endif diff --git a/vcore/src/vcore/SoupMessageSendSync.cpp b/vcore/src/vcore/SoupMessageSendSync.cpp new file mode 100644 index 0000000..bca8e3e --- /dev/null +++ b/vcore/src/vcore/SoupMessageSendSync.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 0.1 + * @file SoupMessageSendSync.cpp + * @brief Implementation of soup synchronous interface. + */ +#include "SoupMessageSendSync.h" + +#include +#include + +#include + +#include + +namespace SoupWrapper { + +SoupMessageSendBase::RequestStatus SoupMessageSendSync::sendSync() +{ + Assert(m_status == STATUS_IDLE); + m_status = STATUS_SEND_SYNC; + + ScopedGMainContext context(g_main_context_new()); + + std::unique_ptr > + proxy(vconf_get_str(VCONFKEY_NETWORK_PROXY), free); + + std::unique_ptr > + proxyURI(soup_uri_new (proxy.get()), soup_uri_free); + + LogDebug("Proxy ptr:" << (void*)proxy.get() << + " Proxy addr: " << proxy.get()); + + for(int tryCount = 0; tryCount < m_tryCount; ++ tryCount){ + LogDebug("Try(" << tryCount << ") to download " << m_host); + + ScopedSoupSession session(soup_session_async_new_with_options( + SOUP_SESSION_ASYNC_CONTEXT, + &*context, + SOUP_SESSION_TIMEOUT, + m_timeout, + SOUP_SESSION_PROXY_URI, + proxyURI.get(), + NULL)); + + ScopedSoupMessage msg; + + msg.Reset(createRequest()); + + if (!msg) { + LogError("Unable to send HTTP request."); + m_status = STATUS_IDLE; + return REQUEST_STATUS_CONNECTION_ERROR; + } + soup_session_send_message(&*session, &*msg); + + // if (SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) + + if (msg->status_code == SOUP_STATUS_OK) { + m_responseBuffer.resize(msg->response_body->length); + memcpy(&m_responseBuffer[0], + msg->response_body->data, + msg->response_body->length); + // We are done. + m_status = STATUS_IDLE; + return REQUEST_STATUS_OK; + } else { + LogWarning("Soup failed with code " << msg->status_code + << " message \n------------\n" + << msg->response_body->data + << "\n--------------\n"); + } + } + + m_status = STATUS_IDLE; + return REQUEST_STATUS_CONNECTION_ERROR; +} + +} // namespave ValidationCore diff --git a/vcore/src/vcore/SoupMessageSendSync.h b/vcore/src/vcore/SoupMessageSendSync.h new file mode 100644 index 0000000..ebb451d --- /dev/null +++ b/vcore/src/vcore/SoupMessageSendSync.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 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. + */ +/*! + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 0.1 + * @file SoupMessageSendSync.h + * @brief Wrapper for soup synchronous interface. + */ +#ifndef _SRC_VALIDATION_CORE_SOUP_MESSAGE_SEND_SYNC_H_ +#define _SRC_VALIDATION_CORE_SOUP_MESSAGE_SEND_SYNC_H_ + +#include "SoupMessageSendBase.h" + +#include + +namespace SoupWrapper { + +class SoupMessageSendSync : public SoupMessageSendBase { + public: + RequestStatus sendSync(); + protected: + typedef WRT::ScopedGPointer ScopedSoupMessage; + typedef WRT::ScopedGPointer ScopedSoupSession; + typedef WRT::ScopedGPointer ScopedGMainContext; +}; + +} // namespace ValidationCore + +#endif diff --git a/vcore/src/vcore/VCore.cpp b/vcore/src/vcore/VCore.cpp new file mode 100644 index 0000000..a3bbfee --- /dev/null +++ b/vcore/src/vcore/VCore.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011 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 VCore.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @brief + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace { +DPL::DB::ThreadDatabaseSupport *threadInterface = NULL; +} // namespace anonymous + +namespace ValidationCore { + +void AttachToThreadRO(void) +{ + Assert(threadInterface); + static bool check = true; + threadInterface->AttachToThread( + DPL::DB::SqlConnection::Flag::RO); + // We can have race condition here but CheckTableExist + // is thread safe and nothing bad will happend. + if (check) { + check = false; + Assert(ThreadInterface().CheckTableExist(DB_CHECKSUM_STR) && + "Not a valid vcore database version"); + } +} + +void AttachToThreadRW(void) +{ + Assert(threadInterface); + static bool check = true; + threadInterface->AttachToThread( + DPL::DB::SqlConnection::Flag::RW); + // We can have race condition here but CheckTableExist + // is thread safe and nothing bad will happend. + if (check) { + check = false; + Assert(ThreadInterface().CheckTableExist(DB_CHECKSUM_STR) && + "Not a valid vcore database version"); + } +} + +void DetachFromThread(void){ + Assert(threadInterface); + threadInterface->DetachFromThread(); +} + +DPL::DB::ThreadDatabaseSupport& ThreadInterface(void) { + Assert(threadInterface); + return *threadInterface; +} + +bool VCoreInit(const std::string& configFilePath, + const std::string& configSchemaPath, + const std::string& databasePath) +{ + if(threadInterface) { + LogDebug("Already Initialized"); + return false; + } + + threadInterface = new DPL::DB::ThreadDatabaseSupport( + databasePath.c_str(), + DPL::DB::SqlConnection::Flag::UseLucene); + + SSL_library_init(); +// g_thread_init(NULL); + g_type_init(); + + LogDebug("Initializing VCore"); + Config &globalConfig = ConfigSingleton::Instance(); + bool returnValue = globalConfig.setXMLConfigPath(configFilePath) && + globalConfig.setXMLSchemaPath(configSchemaPath); + + return returnValue; +} + +void VCoreDeinit() +{ + Assert(threadInterface && "Not initialized or already deinitialized"); + delete threadInterface; + threadInterface = NULL; +} + +} // namespace ValidationCore + diff --git a/vcore/src/vcore/VCore.h b/vcore/src/vcore/VCore.h new file mode 100644 index 0000000..d293563 --- /dev/null +++ b/vcore/src/vcore/VCore.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011 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 VCore.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ +#ifndef _VCORE_SRC_VCORE_VCORE_H_ +#define _VCORE_SRC_VCORE_VCORE_H_ + +#include + +namespace ValidationCore { +/* + * configFilePath - path to XML config file with certificates configuration + * + * configSchemaPath - XMLschema of config file + * + * databasePath - path to database with OCSP/CRL cache. + * + * This function could be run only once. If you call it twice it will + * return false and non data will be set. + * + * This function must be call before AttachToThread function. + */ +bool VCoreInit(const std::string& configFilePath, + const std::string& configSchemaPath, + const std::string& databasePath); + +/* + * This function will free internal structures responsible for db connection. + */ +void VCoreDeinit(void); + +/* + * All thread with are using OCSP/CRL must call AttachToThread function before + * it can call OCSP/CRL. More than one thread could be Attach with OCPS/CRL. + * + * You mast attach thread to OCSP/CRL because OCSP/CRL is using database + * CertificateCachedDAO. For each thread that will be using this database + * vcore must create internal structure (with connection info). + * + */ +void AttachToThreadRO(void); +void AttachToThreadRW(void); +void DetachFromThread(void); + +} // namespace ValidationCore + +#endif // _VCORE_SRC_VCORE_VCORE_H_ + diff --git a/vcore/src/vcore/VCorePrivate.h b/vcore/src/vcore/VCorePrivate.h new file mode 100644 index 0000000..ed85958 --- /dev/null +++ b/vcore/src/vcore/VCorePrivate.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 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 VCore.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ +#ifndef _VCORE_SRC_VCORE_VCOREPRIVATE_H_ +#define _VCORE_SRC_VCORE_VCOREPRIVATE_H_ + +#include +#include +#include +#include + +namespace ValidationCore { +DPL::DB::ThreadDatabaseSupport& ThreadInterface(void); +} // namespace ValidationCore + +#endif // _VCORE_SRC_VCORE_VCORE_H_ + diff --git a/vcore/src/vcore/ValidatorCommon.h b/vcore/src/vcore/ValidatorCommon.h new file mode 100644 index 0000000..8815239 --- /dev/null +++ b/vcore/src/vcore/ValidatorCommon.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011 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 ValidatorCommon.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This file contais definictions of common types used in ValidationCore. + */ +#ifndef _VALIDATORCOMMON_H_ +#define _VALIDATORCOMMON_H_ + +#include +#include +#include + +namespace ValidationCore { +typedef std::set< std::string > ReferenceSet; +typedef std::list< std::string > ObjectList; + +/* + * base deleter func + */ +template +struct ValidatorCoreUniversalFree {}; + +// Template Specialization +#define VC_DECLARE_DELETER(type, function) \ + template <> \ + struct ValidatorCoreUniversalFree { \ + void universal_free(type *ptr){ \ + if (ptr) { \ + function(ptr); } \ + } \ + }; + +template +class AutoPtr +{ + public: + AutoPtr(T *ptr) : + m_data(ptr) + { + } + + AutoPtr(const AutoPtr &second) + { + m_data = second.m_data; + second.m_data = 0; + } + + AutoPtr & operator=(const AutoPtr &second) + { + if (this != &second) { + ValidatorCoreUniversalFree deleter; + deleter.universal_free(m_data); + m_data = second.m_data; + second.m_data = 0; + } + return *this; + } + + /** + * overloaded -> operator, so smart ptr could act as ordinary ptr + */ + T* operator->() + { + return m_data; + } + + ~AutoPtr() + { + ValidatorCoreUniversalFree deleter; + deleter.universal_free(m_data); + } + + /** + * get internal pointer + */ + T* get(void) + { + return m_data; + } + + private: + mutable T *m_data; +}; +} // namespace ValidationCore + +#endif // _VALIDATORCOMMON_H_ diff --git a/vcore/src/vcore/ValidatorFactories.cpp b/vcore/src/vcore/ValidatorFactories.cpp new file mode 100644 index 0000000..c068df7 --- /dev/null +++ b/vcore/src/vcore/ValidatorFactories.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011 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 + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ +#include + +#include +#include + +#include +#include +#include + +namespace ValidationCore { + +const CertificateIdentifier& createCertificateIdentifier() +{ + static CertificateIdentifier certificateIdentifier; + static bool initialized = false; + if (!initialized) { + CertificateConfigReader reader; + std::string file = + ConfigSingleton::Instance().getXMLConfigPath(); + LogDebug("File with fingerprint list is: " << file); + std::string schema = + ConfigSingleton::Instance().getXMLSchemaPath(); + LogDebug("File with fingerprint list schema is: " << schema); + reader.initialize(file, schema); + reader.read(certificateIdentifier); + initialized = true; + } + return certificateIdentifier; +} + +} // namespace ValidationCore diff --git a/vcore/src/vcore/ValidatorFactories.h b/vcore/src/vcore/ValidatorFactories.h new file mode 100644 index 0000000..075eef1 --- /dev/null +++ b/vcore/src/vcore/ValidatorFactories.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 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 + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ +#ifndef _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_VALIDATORFACTORY_H_ +#define _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_VALIDATORFACTORY_H_ + +#include + +namespace ValidationCore { +// First use of CertificateIdentificator should initialized it. +// We do not want to create cyclic dependencies between +// CertificateConfigReader and CertificateIdentificator so +// we are using factory method to create CertificateIdentificator. + +const CertificateIdentifier& createCertificateIdentifier(); +} // namespace ValidationCore + +#endif // _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_VALIDATORFACTORY_H_ diff --git a/vcore/src/vcore/VerificationStatus.cpp b/vcore/src/vcore/VerificationStatus.cpp new file mode 100644 index 0000000..98199ad --- /dev/null +++ b/vcore/src/vcore/VerificationStatus.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011 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. + */ +#include "VerificationStatus.h" + +namespace ValidationCore { +VerificationStatus VerificationStatusSet::convertToStatus() const +{ + if (m_verdictMap & VERIFICATION_STATUS_REVOKED) { + return VERIFICATION_STATUS_REVOKED; + } + + if (m_verdictMap & VERIFICATION_STATUS_VERIFICATION_ERROR) { + return VERIFICATION_STATUS_VERIFICATION_ERROR; + } + + if (m_verdictMap & VERIFICATION_STATUS_ERROR) { + return VERIFICATION_STATUS_ERROR; + } + + if (m_verdictMap & VERIFICATION_STATUS_UNKNOWN) { + return VERIFICATION_STATUS_UNKNOWN; + } + + if (m_verdictMap & VERIFICATION_STATUS_CONNECTION_FAILED) { + return VERIFICATION_STATUS_CONNECTION_FAILED; + } + + if (m_verdictMap & VERIFICATION_STATUS_NOT_SUPPORT) { + return VERIFICATION_STATUS_NOT_SUPPORT; + } + + if (m_verdictMap & VERIFICATION_STATUS_GOOD) { + return VERIFICATION_STATUS_GOOD; + } + + return VERIFICATION_STATUS_ERROR; +} +} // namespace ValidationCore diff --git a/vcore/src/vcore/VerificationStatus.h b/vcore/src/vcore/VerificationStatus.h new file mode 100644 index 0000000..67eecac --- /dev/null +++ b/vcore/src/vcore/VerificationStatus.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2011 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. + */ +#ifndef _SRC_VALIDATION_CORE_VERIFICATION_STATUS_H_ +#define _SRC_VALIDATION_CORE_VERIFICATION_STATUS_H_ + +namespace ValidationCore { +enum VerificationStatus +{ + //! The certificate has not been revoked. + /*! Connection to OCSP responder was successful and the certificate + * has not been revoked. + */ + VERIFICATION_STATUS_GOOD = 1, + + //! The certificate has been revoked. + /*! Connection to OCSP responder was successful and the certificate + * has been revoked. + * RFC2560: "The "revoked" state indicates that the certificate has + * been revoked (either permanantly or temporarily + * (on hold))." + */ + VERIFICATION_STATUS_REVOKED = 1 << 1, + + //! The certificate status is unknown. + /*! Connection to OCSP responder was successful and the certificate + * has unknown status. + * + * RFC2560: "The "unknown" state indicates that the responder + * doesn't know about the certificate being requested." + */ + VERIFICATION_STATUS_UNKNOWN = 1 << 2, + + //! The certificate status was not figure out. + /*! The response from ocsp/crl server contains broken signature. */ + VERIFICATION_STATUS_VERIFICATION_ERROR = 1 << 3, + + //! The certificate status was not figure out. + /*! The certificate does not contain ocsp/crl extension. */ + VERIFICATION_STATUS_NOT_SUPPORT = 1 << 4, + + //! The certificate status was not figure out. + /*! The CertMgr could not connect to OCSP responder. */ + VERIFICATION_STATUS_CONNECTION_FAILED = 1 << 5, + + //! The certificate status is unknown due to internal error inside OCSP + VERIFICATION_STATUS_ERROR = 1 << 6 +}; + +class VerificationStatusSet +{ + public: + VerificationStatusSet() : m_verdictMap(0) + { + } + + inline void add(VerificationStatus status) + { + m_verdictMap |= status; + } + + inline bool contains(VerificationStatus status) const + { + return m_verdictMap & status; + } + + inline bool isEmpty() const + { + return 0 == m_verdictMap; + } + + inline void operator+=(const VerificationStatusSet &second) + { + m_verdictMap |= second.m_verdictMap; + } + + inline void reset() + { + m_verdictMap = 0; + } + + VerificationStatus convertToStatus() const; + + private: + unsigned int m_verdictMap; +}; + +/* TODO this status should be defined in wrt-engine sources */ +enum WidgetVerificationStatus +{ + // All certificate has been veficated and all certificates are good. + // Widget is able to be installed. + WIDGET_VERIFICATION_STATUS_GOOD, + // Some certificate has been revoked. Widget is not able to be installed. + WIDGET_VERIFICATION_STATUS_REVOKED, +}; +} // namespace ValidationCore + +#endif // _SRC_VALIDATION_CORE_VERIFICATION_STATUS_H_ diff --git a/vcore/src/vcore/WacOrigin.cpp b/vcore/src/vcore/WacOrigin.cpp new file mode 100644 index 0000000..7ca0174 --- /dev/null +++ b/vcore/src/vcore/WacOrigin.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2011 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 + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ +#include "WacOrigin.h" + +#include +#include +#include + +#include <> + +#include +#include "ValidatorCommon.h" + +namespace { +const std::string SCHEME_HTTP = "http"; +const std::string SCHEME_HTTPS = "https"; +const int PORT_HTTP = 80; +const int PORT_HTTPS = 443; +} + +namespace ValidationCore { +VC_DECLARE_DELETER(iri_struct, iri_destroy) + +WacOrigin::WacOrigin(const std::string &url) : + m_port(0), + m_parseFailed(false) +{ + parse(url.c_str()); +} + +WacOrigin::WacOrigin(const char *url) : + m_port(0), + m_parseFailed(false) +{ + parse(url); +} + +bool WacOrigin::operator==(const WacOrigin &second) const +{ + if (m_parseFailed || second.m_parseFailed) { + return false; + } + + return (m_scheme == second.m_scheme) && + (m_host == second.m_host) && + (m_port == second.m_port); +} + +void WacOrigin::parse(const char *url) +{ + // Step are taken from algorihtm: + // http://www.w3.org/TR/html5/origin-0.html#origin-0 + + // Step 1 + // Step 2 + AutoPtr iri(iri_parse(url)); + if (!iri.get()) { + m_parseFailed = true; + return; + } + + if (iri->scheme) { + m_scheme = iri->scheme; + } else { + m_parseFailed = true; + return; + } + + // Step 3 - Skip this point. + // WAC 2.0 PRV - we are suport only "http" and "https" schemas. + + // Step 4 - Todo + + // Step 5 + std::transform(m_scheme.begin(), m_scheme.end(), m_scheme.begin(), tolower); + + // Step 6 - we only support "http" and "https" schemas + if ((m_scheme != SCHEME_HTTP) && (m_scheme != SCHEME_HTTPS)) { + m_parseFailed = true; + return; + } + + // Step 7 - Skip. We do not support "file" schema. + + // Step 8 + if (iri->host) { + m_host = iri->host; + } else { + m_parseFailed = true; + return; + } + + // Step 9 + char *output = NULL; + if (IDNA_SUCCESS != + idna_to_ascii_lz(m_host.c_str(), &output, IDNA_USE_STD3_ASCII_RULES)) { + LogError("libidn error"); + m_parseFailed = true; + free(output); + return; + } + m_host = output; + free(output); + + // Step 10 + std::transform(m_host.begin(), m_host.end(), m_host.begin(), ::tolower); + + // Step 11 + if (iri->port) { + m_port = iri->port; + } else { + setPort(); + } + + // Step 12 - Skip it. We do not return anything. + // User should create geters if he need access to schema/host/port. +} + +void WacOrigin::setPort() +{ + if (SCHEME_HTTP == m_scheme) { + m_port = PORT_HTTP; + return; + } else if (SCHEME_HTTPS == m_scheme) { + m_port = PORT_HTTPS; + return; + } else { + LogDebug("Scheme " << m_scheme << " is not support by WAC2.0"); + m_parseFailed = true; + } +} +} // namespace ValidationCore diff --git a/vcore/src/vcore/WacOrigin.h b/vcore/src/vcore/WacOrigin.h new file mode 100644 index 0000000..d706fe3 --- /dev/null +++ b/vcore/src/vcore/WacOrigin.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 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 + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This is stub for HTML5Origin implementation. + * This implementation is compatible with WAC 2.0 PRV requirements + * and is _not_ full compatible with ORIGIN algorithm requirements + * defined in http://www.w3.org/TR/html5/origin-0.html#origin-0 + */ +#ifndef _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_HTML5ORIGIN_H_ +#define _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_HTML5ORIGIN_H_ + +#include + +namespace ValidationCore { +class WacOrigin +{ + public: + + WacOrigin(const std::string &url); + WacOrigin(const char *url); + + bool operator!=(const WacOrigin &second) const + { + return !(operator==(second)); + } + + bool operator==(const WacOrigin &second) const; + + private: + void parse(const char *url); + void setPort(); + + std::string m_scheme; + std::string m_host; + int m_port; + bool m_parseFailed; // if parsing failed we should return unique identifier +}; +} //namespace ValidationCore + +#endif // _WRT_ENGINE_SRC_INSTALLER_CORE_VALIDATION_CORE_HTML5ORIGIN_H_ diff --git a/vcore/src/vcore/XmlsecAdapter.cpp b/vcore/src/vcore/XmlsecAdapter.cpp new file mode 100644 index 0000000..8ba3a81 --- /dev/null +++ b/vcore/src/vcore/XmlsecAdapter.cpp @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2011 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 XmlsecAdapter.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ + +/* + * Copyright (C) 2002-2003 Aleksey Sanin. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include +#include + +#include +#include +#include + +#ifndef XMLSEC_NO_XSLT +#include +#endif /* XMLSEC_NO_XSLT */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "XmlsecAdapter.h" +#include +IMPLEMENT_SINGLETON(ValidationCore::XmlSec) + +namespace { + +struct FileWrapper { + FileWrapper(void *argFile, bool argReleased) + : file(argFile) + , released(argReleased) + {} + void *file; + bool released; +}; + +} // anonymous namespace + +namespace ValidationCore { +VC_DECLARE_DELETER(xmlSecKeysMngr, xmlSecKeysMngrDestroy) + +static const char* DIGEST_MD5 = "md5"; + +std::string XmlSec::s_prefixPath; + +int XmlSec::fileMatchCallback(const char *filename) +{ + std::string path = s_prefixPath + filename; + return xmlFileMatch(path.c_str()); +} + +void* XmlSec::fileOpenCallback(const char *filename) +{ + std::string path = s_prefixPath + filename; + LogDebug("Xmlsec opening: " << path); + return new FileWrapper(xmlFileOpen(path.c_str()),false); +} + +int XmlSec::fileReadCallback(void *context, + char *buffer, + int len) +{ + FileWrapper *fw = static_cast(context); + if (fw->released) { + return 0; + } + int output = xmlFileRead(fw->file, buffer, len); + if (output == 0) { + fw->released = true; + xmlFileClose(fw->file); + } + return output; +} + +int XmlSec::fileCloseCallback(void *context) +{ + FileWrapper *fw = static_cast(context); + int output = 0; + if (!(fw->released)) { + output = xmlFileClose(fw->file); + } + delete fw; + return output; +} + +void XmlSec::fileExtractPrefix(XmlSecContext *context) +{ + if (!(context->workingDirectory.empty())) { + s_prefixPath = context->workingDirectory; + return; + } + + s_prefixPath = context->signatureFile; + size_t pos = s_prefixPath.rfind('/'); + if (pos == std::string::npos) { + s_prefixPath.clear(); + } else { + s_prefixPath.erase(pos + 1, std::string::npos); + } +} + +XmlSec::XmlSec() : + m_initialized(false) +{ + LIBXML_TEST_VERSION + xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + xmlSubstituteEntitiesDefault(1); +#ifndef XMLSEC_NO_XSLT + xmlIndentTreeOutput = 1; +#endif + + if (xmlSecInit() < 0) { + LogError("Xmlsec initialization failed."); + ThrowMsg(Exception::InternalError, "Xmlsec initialization failed."); + } + + if (xmlSecCheckVersion() != 1) { + xmlSecShutdown(); + LogError("Loaded xmlsec library version is not compatible."); + ThrowMsg(Exception::InternalError, + "Loaded xmlsec library version is not compatible."); + } + +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if (xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + xmlSecShutdown(); + LogError( + "Error: unable to load default xmlsec-crypto library. Make sure " + "that you have it installed and check shared libraries path " + "(LD_LIBRARY_PATH) envornment variable."); + ThrowMsg(Exception::InternalError, + "Unable to load default xmlsec-crypto library."); + } +#endif + + if (xmlSecCryptoAppInit(NULL) < 0) { + xmlSecShutdown(); + LogError("Crypto initialization failed."); + ThrowMsg(Exception::InternalError, "Crypto initialization failed."); + } + + if (xmlSecCryptoInit() < 0) { + xmlSecCryptoAppShutdown(); + xmlSecShutdown(); + LogError("Xmlsec-crypto initialization failed."); + ThrowMsg(Exception::InternalError, + "Xmlsec-crypto initialization failed."); + } + + m_initialized = true; +} + +void XmlSec::deinitialize(void) +{ + Assert(m_initialized); + + /* Shutdown xmlsec-crypto library */ + xmlSecCryptoShutdown(); + + /* Shutdown crypto library */ + xmlSecCryptoAppShutdown(); + + /* Shutdown xmlsec library */ + xmlSecShutdown(); + + /* Shutdown libxslt/libxml */ +#ifndef XMLSEC_NO_XSLT + xsltCleanupGlobals(); +#endif /* XMLSEC_NO_XSLT */ + + s_prefixPath.clear(); + m_initialized = false; +} + +XmlSec::~XmlSec() +{ + if (m_initialized) { + deinitialize(); + } +} + +XmlSec::Result XmlSec::validateFile(XmlSecContext *context, + xmlSecKeysMngrPtr mngr) +{ + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlSecDSigCtxPtr dsigCtx = NULL; + int size, res = -1; + + fileExtractPrefix(context); + LogDebug("Prefix path: " << s_prefixPath); + + xmlSecIOCleanupCallbacks(); + + xmlSecIORegisterCallbacks( + fileMatchCallback, + fileOpenCallback, + fileReadCallback, + fileCloseCallback); + + /* load file */ + doc = xmlParseFile(context->signatureFile.c_str()); + if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)) { + LogWarning("Unable to parse file " << context->signatureFile); + goto done; + } + + /* find start node */ + node = xmlSecFindNode(xmlDocGetRootElement( + doc), xmlSecNodeSignature, xmlSecDSigNs); + if (node == NULL) { + LogWarning("Start node not found in " << context->signatureFile); + goto done; + } + + /* create signature context */ + dsigCtx = xmlSecDSigCtxCreate(mngr); + if (dsigCtx == NULL) { + LogError("Failed to create signature context."); + goto done; + } + + if (context->allowBrokenChain) { + dsigCtx->keyInfoReadCtx.flags |= + XMLSEC_KEYINFO_FLAGS_ALLOW_BROKEN_CHAIN; + } + + if (context->validationTime) { + LogDebug("Setting validation time."); + dsigCtx->keyInfoReadCtx.certsVerificationTime = context->validationTime; + } + + /* Verify signature */ + if (xmlSecDSigCtxVerify(dsigCtx, node) < 0) { + LogWarning("Signature verify error."); + goto done; + } + + if (dsigCtx->keyInfoReadCtx.flags2 & + XMLSEC_KEYINFO_ERROR_FLAGS_BROKEN_CHAIN) { + LogWarning("XMLSEC_KEYINFO_FLAGS_ALLOW_BROKEN_CHAIN was set to true!"); + LogWarning("Signature contains broken chain!"); + context->errorBrokenChain = true; + } + + /* print verification result to stdout */ + if (dsigCtx->status == xmlSecDSigStatusSucceeded) { + LogDebug("Signature is OK"); + res = 0; + } else { + LogDebug("Signature is INVALID"); + goto done; + } + + if (dsigCtx->c14nMethod && dsigCtx->c14nMethod->id && + dsigCtx->c14nMethod->id->name) { + LogInfo("Canonicalization method: " << + reinterpret_cast(dsigCtx->c14nMethod->id->name)); + } + + size = xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences)); + for (int i = 0; i < size; ++i) { + xmlSecDSigReferenceCtxPtr dsigRefCtx = + (xmlSecDSigReferenceCtxPtr)xmlSecPtrListGetItem(&(dsigCtx-> + signedInfoReferences), + i); + if (dsigRefCtx && dsigRefCtx->uri) { + if (dsigRefCtx->digestMethod && dsigRefCtx->digestMethod->id && + dsigRefCtx->digestMethod->id->name) { + const char* pDigest = + reinterpret_cast(dsigRefCtx->digestMethod->id + ->name); + std::string strDigest(pDigest); + LogInfo("reference digest method: " << + reinterpret_cast(dsigRefCtx->digestMethod + ->id + ->name)); + if (strDigest == DIGEST_MD5) { + LogWarning("MD5 digest method used! Please use sha"); + res = -1; + break; + } + } + context->referenceSet.insert(std::string(reinterpret_cast( + dsigRefCtx->uri))); + } + } + +done: + /* cleanup */ + if (dsigCtx != NULL) { + xmlSecDSigCtxDestroy(dsigCtx); + } + + if (doc != NULL) { + xmlFreeDoc(doc); + } + + if (res) { + return ERROR_INVALID_SIGNATURE; + } + return NO_ERROR; +} + +void XmlSec::loadDERCertificateMemory(XmlSecContext *context, + xmlSecKeysMngrPtr mngr) +{ + unsigned char *derCertificate = NULL; + int size = i2d_X509(context->certificatePtr->getX509(), &derCertificate); + + if (!derCertificate) { + LogError("Failed during x509 conversion to der format."); + ThrowMsg(Exception::InternalError, + "Failed during x509 conversion to der format."); + } + + if (xmlSecCryptoAppKeysMngrCertLoadMemory(mngr, + derCertificate, + size, + xmlSecKeyDataFormatDer, + xmlSecKeyDataTypeTrusted) < 0) { + OPENSSL_free(derCertificate); + LogError("Failed to load der certificate from memory."); + ThrowMsg(Exception::InternalError, + "Failed to load der certificate from memory."); + } + + OPENSSL_free(derCertificate); +} + +void XmlSec::loadPEMCertificateFile(XmlSecContext *context, + xmlSecKeysMngrPtr mngr) +{ + if (xmlSecCryptoAppKeysMngrCertLoad(mngr, + context->certificatePath.c_str(), + xmlSecKeyDataFormatPem, + xmlSecKeyDataTypeTrusted) < 0) { + LogError("Failed to load PEM certificate from file."); + ThrowMsg(Exception::InternalError, + "Failed to load PEM certificate from file."); + } +} + +XmlSec::Result XmlSec::validate(XmlSecContext *context) +{ + Assert(context); + Assert(!(context->signatureFile.empty())); + Assert(context->certificatePtr.Get() || !(context->certificatePath.empty())); + + if (!m_initialized) { + LogError("XmlSec is not initialized."); + ThrowMsg(Exception::InternalError, "XmlSec is not initialized"); + } + + AutoPtr mngr(xmlSecKeysMngrCreate()); + + if (!mngr.get()) { + LogError("Failed to create keys manager."); + ThrowMsg(Exception::InternalError, "Failed to create keys manager."); + } + + if (xmlSecCryptoAppDefaultKeysMngrInit(mngr.get()) < 0) { + LogError("Failed to initialize keys manager."); + ThrowMsg(Exception::InternalError, "Failed to initialize keys manager."); + } + context->referenceSet.clear(); + + if (context->certificatePtr.Get()) { + loadDERCertificateMemory(context, mngr.get()); + } + + if (!context->certificatePath.empty()) { + loadPEMCertificateFile(context, mngr.get()); + } + + return validateFile(context, mngr.get()); +} +} // namespace ValidationCore diff --git a/vcore/src/vcore/XmlsecAdapter.h b/vcore/src/vcore/XmlsecAdapter.h new file mode 100644 index 0000000..4104c88 --- /dev/null +++ b/vcore/src/vcore/XmlsecAdapter.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2011 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 XmlSecAdapter.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief + */ +#ifndef _XMLSECADAPTER_H_ +#define _XMLSECADAPTER_H_ + +#include + +#include +#include +#include + +#include "Certificate.h" +#include "ValidatorCommon.h" + +namespace ValidationCore { +class XmlSec : public DPL::Noncopyable +{ + public: + + struct XmlSecContext + { + /* You _must_ set one of the value: certificatePath or certificate. */ + XmlSecContext() : + validationTime(0), + allowBrokenChain(false), + errorBrokenChain(false) + { + } + + /* + * Absolute path to signature file. + */ + std::string signatureFile; + /* + * Direcotory with signed data. + * If you leave it empty xmlsec will use directory extracted + * from signatureFile. + */ + std::string workingDirectory; + /* + * Path to trusted certificate. + */ + std::string certificatePath; + /* + * Trusted certificate. In most cases it should be Root CA certificate. + */ + CertificatePtr certificatePtr; + /* + * Validation date. + * 0 - uses current time. + */ + time_t validationTime; + /* + * Input parameter. + * If true, signature validation will not be interrupted by chain error. + * If true and chain is broken then the value errorBrokenChain will be + * set to true. + */ + bool allowBrokenChain; + /* + * Output parameter. + * This will be set if chain is incomplete or broken. + */ + bool errorBrokenChain; + /* + * Output parameter. + * Reference checked by xmlsec + */ + ReferenceSet referenceSet; + }; + + enum Result + { + NO_ERROR, + ERROR_INVALID_SIGNATURE + }; + + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, InternalError) + }; + + /* + * Context - input/output param. + */ + Result validate(XmlSecContext *context); + protected: + XmlSec(); + ~XmlSec(); + private: + void deinitialize(void); + + void loadDERCertificateMemory(XmlSecContext *context, + xmlSecKeysMngrPtr mngr); + void loadPEMCertificateFile(XmlSecContext *context, + xmlSecKeysMngrPtr mngr); + Result validateFile(XmlSecContext *context, + xmlSecKeysMngrPtr mngr); + + bool m_initialized; + + static std::string s_prefixPath; + static int fileMatchCallback(const char *filename); + static void* fileOpenCallback(const char *filename); + static int fileReadCallback(void *context, + char *buffer, + int len); + static int fileCloseCallback(void *context); + static void fileExtractPrefix(XmlSecContext *context); +}; + +typedef DPL::Singleton XmlSecSingleton; +} // namespace ValidationCore +#endif // _XMLSECVERIFICATOR_H_ diff --git a/vcore/src/vcore/api.cpp b/vcore/src/vcore/api.cpp new file mode 100644 index 0000000..f4e37af --- /dev/null +++ b/vcore/src/vcore/api.cpp @@ -0,0 +1,1525 @@ +/** + * Copyright (c) 2011 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 api.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @author Jacek Migacz (j.migacz@samsung.com) + * @version 1.0 + * @brief This is part of C-api proposition for cert-svc. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace ValidationCore; + +namespace { + +typedef std::unique_ptr > ScopedCertCtx; + +class CRLCacheCAPI : public CRLCacheInterface { +public: + CRLCacheCAPI( + CertSvcCrlCacheWrite crlWrite, + CertSvcCrlCacheRead crlRead, + CertSvcCrlFree crlFree, + void *userParam) + : m_crlWrite(crlWrite) + , m_crlRead(crlRead) + , m_crlFree(crlFree) + , m_userParam(userParam) + {} + + bool getCRLResponse(CRLCachedData *ptr){ + if (!m_crlRead || !m_crlFree) + return false; + + char *buffer; + int size; + + bool result = m_crlRead( + ptr->distribution_point.c_str(), + &buffer, + &size, + &(ptr->next_update_time), + m_userParam); + + if (result) { + ptr->crl_body.clear(); + ptr->crl_body.append(buffer, size); + m_crlFree(buffer, m_userParam); + } + + return result; + } + void setCRLResponse(CRLCachedData *ptr){ + if (m_crlWrite) { + m_crlWrite( + ptr->distribution_point.c_str(), + ptr->crl_body.c_str(), + ptr->crl_body.size(), + ptr->next_update_time, + m_userParam); + } + } + +private: + CertSvcCrlCacheWrite m_crlWrite; + CertSvcCrlCacheRead m_crlRead; + CertSvcCrlFree m_crlFree; + void *m_userParam; +}; + +class CertSvcInstanceImpl { +public: + CertSvcInstanceImpl() + : m_certificateCounter(0) + , m_idListCounter(0) + , m_stringListCounter(0) + , m_crlWrite(NULL) + , m_crlRead(NULL) + , m_crlFree(NULL) + {} + + ~CertSvcInstanceImpl(){ + FOREACH(it, m_allocatedStringSet) { + delete[] *it; + } + } + + inline void reset(){ + m_certificateCounter = 0; + m_certificateMap.clear(); + m_idListCounter = 0; + m_idListMap.clear(); + m_stringListCounter = 0; + m_stringListMap.clear(); + + FOREACH(it, m_allocatedStringSet) { + delete[] *it; + } + + m_allocatedStringSet.clear(); + } + + inline int addCert(const CertificatePtr &cert) { + m_certificateMap[m_certificateCounter] = cert; + return m_certificateCounter++; + } + + inline void removeCert(const CertSvcCertificate &cert) { + auto iter = m_certificateMap.find(cert.privateHandler); + if (iter != m_certificateMap.end()) { + m_certificateMap.erase(iter); + } + } + + inline int getCertFromList( + const CertSvcCertificateList &handler, + int position, + CertSvcCertificate *certificate) + { + auto iter = m_idListMap.find(handler.privateHandler); + if (iter == m_idListMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + if (position >= static_cast(iter->second.size())) { + return CERTSVC_WRONG_ARGUMENT; + } + certificate->privateInstance = handler.privateInstance; + certificate->privateHandler = (iter->second)[position]; + return CERTSVC_SUCCESS; + } + + inline int getCertListLen(const CertSvcCertificateList &handler, int *len) { + auto iter = m_idListMap.find(handler.privateHandler); + if (iter == m_idListMap.end() || !len) { + return CERTSVC_WRONG_ARGUMENT; + } + *len = (iter->second).size(); + return CERTSVC_SUCCESS; + } + + inline void removeCertList(const CertSvcCertificateList &handler) { + auto iter = m_idListMap.find(handler.privateHandler); + if (iter != m_idListMap.end()) + m_idListMap.erase(iter); + } + + inline int isSignedBy(const CertSvcCertificate &child, + const CertSvcCertificate &parent, + int *status) + { + auto citer = m_certificateMap.find(child.privateHandler); + if (citer == m_certificateMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + auto piter = m_certificateMap.find(parent.privateHandler); + if (piter == m_certificateMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + + if (citer->second->isSignedBy(piter->second)) { + *status = CERTSVC_TRUE; + } else { + *status = CERTSVC_FALSE; + } + return CERTSVC_SUCCESS; + } + + inline int getField(const CertSvcCertificate &cert, + CertSvcCertificateField field, + CertSvcString *buffer) + { + auto iter = m_certificateMap.find(cert.privateHandler); + if (iter == m_certificateMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + + auto certPtr = iter->second; + DPL::OptionalString result; + switch(field) { + case CERTSVC_SUBJECT: + result = DPL::OptionalString(certPtr->getOneLine()); + break; + case CERTSVC_ISSUER: + result = DPL::OptionalString(certPtr->getOneLine(Certificate::FIELD_ISSUER)); + break; + case CERTSVC_SUBJECT_COMMON_NAME: + result = certPtr->getCommonName(); + break; + case CERTSVC_SUBJECT_COUNTRY_NAME: + result = certPtr->getCountryName(); + break; + case CERTSVC_SUBJECT_STATE_NAME: + result = certPtr->getStateOrProvinceName(); + break; + case CERTSVC_SUBJECT_ORGANIZATION_NAME: + result = certPtr->getOrganizationName(); + break; + case CERTSVC_SUBJECT_ORGANIZATION_UNIT_NAME: + result = certPtr->getOrganizationalUnitName(); + break; + case CERTSVC_ISSUER_COMMON_NAME: + result = certPtr->getCommonName(Certificate::FIELD_ISSUER); + break; + case CERTSVC_ISSUER_STATE_NAME: + result = certPtr->getStateOrProvinceName(Certificate::FIELD_ISSUER); + break; + case CERTSVC_ISSUER_ORGANIZATION_NAME: + result = certPtr->getOrganizationName(Certificate::FIELD_ISSUER); + break; + case CERTSVC_ISSUER_ORGANIZATION_UNIT_NAME: + result = certPtr->getOrganizationalUnitName(Certificate::FIELD_ISSUER); + break; + case CERTSVC_VERSION: + { + std::stringstream stream; + stream << (certPtr->getVersion()+1); + result = DPL::OptionalString(DPL::FromUTF8String(stream.str())); + break; + } + case CERTSVC_SERIAL_NUMBER: + result = DPL::OptionalString(certPtr->getSerialNumberString()); + break; + case CERTSVC_KEY_USAGE: + result = DPL::OptionalString(certPtr->getKeyUsageString()); + break; + case CERTSVC_KEY: + result = DPL::OptionalString(certPtr->getPublicKeyString()); + break; + case CERTSVC_SIGNATURE_ALGORITHM: + result = DPL::OptionalString(certPtr->getSignatureAlgorithmString()); + break; + default: + break; + } + + if (result.IsNull()) { + buffer->privateHandler = NULL; + buffer->privateLength = 0; + buffer->privateInstance = cert.privateInstance; + return CERTSVC_SUCCESS; + } + std::string output = DPL::ToUTF8String(*result); + + char *cstring = new char[output.size()+1]; + strncpy(cstring, output.c_str(), output.size()+1); + + buffer->privateHandler = cstring; + buffer->privateLength = output.size(); + buffer->privateInstance = cert.privateInstance; + + m_allocatedStringSet.insert(cstring); + + return CERTSVC_SUCCESS; + } + + inline int getNotAfter(const CertSvcCertificate &cert, + time_t *time) + { + auto iter = m_certificateMap.find(cert.privateHandler); + if (iter == m_certificateMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + *time = iter->second->getNotAfter(); + return CERTSVC_SUCCESS; + } + + inline int getNotBefore(const CertSvcCertificate &cert, + time_t *time) + { + auto iter = m_certificateMap.find(cert.privateHandler); + if (iter == m_certificateMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + *time = iter->second->getNotBefore(); + return CERTSVC_SUCCESS; + } + + inline int isRootCA(const CertSvcCertificate &cert, int *status){ + auto iter = m_certificateMap.find(cert.privateHandler); + if (iter == m_certificateMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + if (iter->second->isRootCert()) { + *status = CERTSVC_TRUE; + } else { + *status = CERTSVC_FALSE; + } + return CERTSVC_SUCCESS; + } + + inline int getCrl(const CertSvcCertificate &cert, CertSvcStringList *handler){ + auto iter = m_certificateMap.find(cert.privateHandler); + if (iter == m_certificateMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + int position = m_stringListCounter++; + + std::list temp = iter->second->getCrlUris(); + std::copy(temp.begin(), + temp.end(), + back_inserter(m_stringListMap[position])); + + handler->privateHandler = position; + handler->privateInstance = cert.privateInstance; + + return CERTSVC_SUCCESS; + } + + inline int getStringFromList( + const CertSvcStringList &handler, + int position, + CertSvcString *buffer) + { + buffer->privateHandler = NULL; + buffer->privateLength = 0; + + auto iter = m_stringListMap.find(handler.privateHandler); + if (iter == m_stringListMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + if (position >= (int)iter->second.size()) { + return CERTSVC_WRONG_ARGUMENT; + } + const std::string &data = iter->second.at(position); + int size = data.size(); + char *cstring = new char[size+1]; + if (!cstring) { + return CERTSVC_FAIL; + } + + strncpy(cstring, data.c_str(), data.size()+1); + + buffer->privateHandler = cstring; + buffer->privateLength = data.size(); + buffer->privateInstance = handler.privateInstance; + + m_allocatedStringSet.insert(cstring); + + return CERTSVC_SUCCESS; + } + + inline int getStringListLen( + const CertSvcStringList &handler, + int *size) + { + auto iter = m_stringListMap.find(handler.privateHandler); + if (iter == m_stringListMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + *size = (int) iter->second.size(); + return CERTSVC_SUCCESS; + } + + inline void removeStringList(const CertSvcStringList &handler) + { + m_stringListMap.erase(m_stringListMap.find(handler.privateHandler)); + } + + inline void removeString(const CertSvcString &handler) + { + auto iter = m_allocatedStringSet.find(handler.privateHandler); + if (iter != m_allocatedStringSet.end()) { + delete[] *iter; + m_allocatedStringSet.erase(iter); + } + } + + inline int certificateSearch( + CertSvcInstance instance, + CertSvcCertificateField field, + const char *value, + CertSvcCertificateList *handler) + { + int result; + search_field fieldId = SEARCH_FIELD_END; + + switch(field){ + case CERTSVC_SUBJECT: + fieldId = SUBJECT_STR; + break; + case CERTSVC_ISSUER: + fieldId = ISSUER_STR; + break; + case CERTSVC_SUBJECT_COMMON_NAME: + fieldId = SUBJECT_COMMONNAME; + break; + default: + LogError("Not implemented!"); + return CERTSVC_WRONG_ARGUMENT; + } + + ScopedCertCtx ctx(cert_svc_cert_context_init(), + cert_svc_cert_context_final); + + if (ctx.get() == NULL) { + LogWarning("Error in cert_svc_cert_context_init."); + return CERTSVC_FAIL; + } + + LogDebug("Match string: " << value); + result = cert_svc_search_certificate(ctx.get(), fieldId, const_cast(value)); + LogDebug("Search finished!"); + + if (CERT_SVC_ERR_NO_ERROR != result) { + LogWarning("Error during certificate search"); + return CERTSVC_FAIL; + } + + cert_svc_filename_list *fileList = ctx.get()->fileNames; + + int listId = m_idListCounter++; + std::vector &list = m_idListMap[listId]; + handler->privateHandler = listId; + handler->privateInstance = instance; + + for(;fileList != NULL; fileList = fileList->next) { + ScopedCertCtx ctx2(cert_svc_cert_context_init(), + cert_svc_cert_context_final); + if (ctx2.get() == NULL) { + LogWarning("Error in cert_svc_cert_context_init."); + return CERTSVC_FAIL; + } + + // TODO add read_certifcate_from_file function to Certificate.h + if (CERT_SVC_ERR_NO_ERROR != + cert_svc_load_file_to_context(ctx2.get(), fileList->filename)) + { + LogWarning("Error in cert_svc_load_file_to_context"); + return CERTSVC_FAIL; + } + int certId = addCert(CertificatePtr(new Certificate(*(ctx2.get()->certBuf)))); + list.push_back(certId); + } + return CERTSVC_SUCCESS; + } + + inline int sortCollection(CertSvcCertificate *certificate_array, int size) { + if (size < 2) { + return CERTSVC_WRONG_ARGUMENT; + } + + for(int i=1; i translator; + + for(int i=0; isecond.Get()] = pos; + certList.push_back(cert->second); + } + + CertificateCollection collection; + collection.load(certList); + + if (!collection.sort()) { + return CERTSVC_FAIL; + } + + auto chain = collection.getChain(); + + int i=0; + for (auto iter = chain.begin(); iter != chain.end() && iGet()]; + } + + return CERTSVC_SUCCESS; + } + + inline int getX509Copy(const CertSvcCertificate &certificate, X509** cert) + { + auto it = m_certificateMap.find(certificate.privateHandler); + if (it == m_certificateMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + *cert = X509_dup(it->second->getX509()); + return CERTSVC_SUCCESS; + } + + inline int saveToFile(const CertSvcCertificate &certificate, + const char *location) + { + auto it = m_certificateMap.find(certificate.privateHandler); + if (it == m_certificateMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + FILE *out; + if (NULL == (out = fopen(location, "w"))) { + return CERTSVC_FAIL; + } + if (0 == i2d_X509_fp(out, it->second->getX509())) { + fclose(out); + return CERTSVC_FAIL; + } + fclose(out); + return CERTSVC_SUCCESS; + } + + inline int ocspCheck(const CertSvcCertificate *chain, + int chain_size, + const CertSvcCertificate *trusted, + int trusted_size, + const char *url, + int *status) + { + auto instance = chain[0].privateInstance.privatePtr; + + for(int i=1; isecond); + } + + for(int i=0; isecond); + } + + OCSP ocsp; +// ocsp.setDigestAlgorithmForCertId(OCSP::SHA1); +// ocsp.setDigestAlgorithmForRequest(OCSP::SHA1); + ocsp.setTrustedStore(trustedList); + + if (url) { + ocsp.setUseDefaultResponder(true); + ocsp.setDefaultResponder(url); + } + + CertificateCollection collection; + collection.load(chainList); + if (!collection.sort()) { + return CERTSVC_WRONG_ARGUMENT; + } + + chainList = collection.getChain(); + + VerificationStatusSet statusSet = ocsp.validateCertificateList(chainList); + + int ret = 0; + if (statusSet.contains(VERIFICATION_STATUS_GOOD)) { + ret |= CERTSVC_OCSP_GOOD; + } + if (statusSet.contains(VERIFICATION_STATUS_REVOKED)) { + ret |= CERTSVC_OCSP_REVOKED; + } + if (statusSet.contains(VERIFICATION_STATUS_UNKNOWN)) { + ret |= CERTSVC_OCSP_UNKNOWN; + } + if (statusSet.contains(VERIFICATION_STATUS_VERIFICATION_ERROR)) { + ret |= CERTSVC_OCSP_VERIFICATION_ERROR; + } + if (statusSet.contains(VERIFICATION_STATUS_NOT_SUPPORT)) { + ret |= CERTSVC_OCSP_NO_SUPPORT; + } + if (statusSet.contains(VERIFICATION_STATUS_ERROR)) { + ret |= CERTSVC_OCSP_ERROR; + } + + *status = ret; + return CERTSVC_SUCCESS; + } + + inline int verify( + CertSvcCertificate certificate, + CertSvcString &message, + CertSvcString &signature, + const char *algorithm, + int *status) + { + int result = CERTSVC_FAIL; + + if (!status) { + return CERTSVC_WRONG_ARGUMENT; + } + + auto it = m_certificateMap.find(certificate.privateHandler); + if (it == m_certificateMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + + OpenSSL_add_all_digests(); + + int temp; + EVP_MD_CTX* mdctx = NULL; + const EVP_MD * md = NULL; + X509 *cert = it->second->getX509(); + EVP_PKEY *pkey = NULL; + + if (cert == NULL) { + goto err; + } + + pkey = X509_get_pubkey(cert); + + if (pkey == NULL) { + goto err; + } + + if (algorithm == NULL) { + md = EVP_get_digestbyobj(cert->cert_info->signature->algorithm); + } else { + md = EVP_get_digestbyname(algorithm); + } + + if (md == NULL) { + result = CERTSVC_INVALID_ALGORITHM; + goto err; + } + + mdctx = EVP_MD_CTX_create(); + + if (mdctx == NULL) { + goto err; + } + + if (EVP_VerifyInit_ex(mdctx, md, NULL) != 1) { + goto err; + } + + if (EVP_VerifyUpdate(mdctx, message.privateHandler, message.privateLength) != 1) { + goto err; + } + + temp = EVP_VerifyFinal(mdctx, + reinterpret_cast(signature.privateHandler), + signature.privateLength, + pkey); + + if (temp == 0) { + *status = CERTSVC_INVALID_SIGNATURE; + result = CERTSVC_SUCCESS; + } else if (temp == 1) { + *status = CERTSVC_SUCCESS; + result = CERTSVC_SUCCESS; + } + + err: + if (mdctx != NULL) + EVP_MD_CTX_destroy(mdctx); + if (pkey != NULL) + EVP_PKEY_free(pkey); + return result; + } + + inline int base64Encode( + const CertSvcString &message, + CertSvcString *base64) + { + if (!base64) { + return CERTSVC_WRONG_ARGUMENT; + } + std::string info(message.privateHandler, message.privateLength); + Base64Encoder base; + base.reset(); + base.append(info); + base.finalize(); + info = base.get(); + char *ptr = new char[info.size()+1]; + memcpy(ptr, info.c_str(), info.size()+1); + m_allocatedStringSet.insert(ptr); + base64->privateHandler = ptr; + base64->privateLength = info.size(); + base64->privateInstance = message.privateInstance; + return CERTSVC_SUCCESS; + } + + int base64Decode( + const CertSvcString &base64, + CertSvcString *message) + { + if (!message) { + return CERTSVC_WRONG_ARGUMENT; + } + std::string info(base64.privateHandler, base64.privateLength); + Base64Decoder base; + base.reset(); + base.append(info); + if (!base.finalize()) { + return CERTSVC_FAIL; + } + info = base.get(); + char *ptr = new char[info.size()+1]; + memcpy(ptr, info.c_str(), info.size()+1); + m_allocatedStringSet.insert(ptr); + message->privateHandler = ptr; + message->privateLength = info.size(); + message->privateInstance = base64.privateInstance; + return CERTSVC_SUCCESS; + } + + inline int stringNew( + CertSvcInstance &instance, + const char *str, + int size, + CertSvcString *output) + { + if (!output) { + return CERTSVC_WRONG_ARGUMENT; + } + + int allocSize = size; + + if (str[allocSize-1] != 0) + allocSize++; + + char *ptr = new char[allocSize]; + memcpy(ptr, str, size); + ptr[allocSize-1] = 0; + + output->privateHandler = ptr; + output->privateLength = size; + output->privateInstance = instance; + return CERTSVC_SUCCESS; + } + + inline void setCRLFunction( + CertSvcCrlCacheWrite writePtr, + CertSvcCrlCacheRead readPtr, + CertSvcCrlFree freePtr) + { + m_crlWrite = writePtr; + m_crlRead = readPtr; + m_crlFree = freePtr; + } + + inline int crlCheck( + CertSvcCertificate certificate, + CertSvcCertificate *trustedStore, + int storeSize, + int force, + int *status, + void *userParam) + { + for(int i=1; isecond); + } + + auto iter = m_certificateMap.find(certificate.privateHandler); + if (iter == m_certificateMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + if (iter->second->getCrlUris().empty()) { + *status = CERTSVC_CRL_NO_SUPPORT; + return CERTSVC_SUCCESS; + } + crl.updateList(iter->second, force ? CRL::UPDATE_ON_DEMAND: CRL::UPDATE_ON_EXPIRED); + CRL::RevocationStatus st = crl.checkCertificate(iter->second); + *status = 0; + + if (!st.isCRLValid) { + *status |= CERTSVC_CRL_VERIFICATION_ERROR; + return CERTSVC_SUCCESS; + } + + if (st.isRevoked) { + *status |= CERTSVC_CRL_REVOKED; + } else { + *status |= CERTSVC_CRL_GOOD; + } + + return CERTSVC_SUCCESS; + } + + inline int certificateVerify( + CertSvcCertificate certificate, + CertSvcCertificate *trusted, + int trustedSize, + CertSvcCertificate *untrusted, + int untrustedSize, + int *status) + { + if (!trusted || !status) { + return CERTSVC_WRONG_ARGUMENT; + } + auto iter = m_certificateMap.find(certificate.privateHandler); + if (iter == m_certificateMap.end()) { + return CERTSVC_WRONG_ARGUMENT; + } + + X509 *cert = iter->second->getX509(); + X509_STORE *store = X509_STORE_new(); + STACK_OF(X509) *ustore = sk_X509_new_null(); + + for (int i=0; isecond->getX509()); + } + + for (int i=0; isecond->getX509()); + } + X509_STORE_CTX context; + X509_STORE_CTX_init(&context, store, cert, ustore); + int result = X509_verify_cert(&context); + X509_STORE_CTX_cleanup(&context); + X509_STORE_free(store); + sk_X509_free(ustore); + + if (result == 1) { + *status = CERTSVC_SUCCESS; + } else { + *status = CERTSVC_FAIL; + } + return CERTSVC_SUCCESS; + } + + inline int pkcsNameIsUnique( + CertSvcString pfxIdString, + int *is_unique) + { + gboolean exists; + int result = c_certsvc_pkcs12_alias_exists(pfxIdString.privateHandler, &exists); + *is_unique = !exists; + return result; + } + + inline int pkcsImport( + CertSvcString path, + CertSvcString pass, + CertSvcString pfxIdString) + { + return c_certsvc_pkcs12_import(path.privateHandler, pass.privateHandler, pfxIdString.privateHandler); + } + + inline int getPkcsIdList( + CertSvcInstance &instance, + CertSvcStringList *handler) + { + gchar **aliases; + gsize i, naliases; + std::vector output; + int result; + + result = c_certsvc_pkcs12_aliases_load(&aliases, &naliases); + if(result != CERTSVC_SUCCESS) + return result; + for(i = 0; i < naliases; i++) + output.push_back(std::string(aliases[i])); + c_certsvc_pkcs12_aliases_free(aliases); + + int position = m_stringListCounter++; + m_stringListMap[position] = output; + + handler->privateHandler = position; + handler->privateInstance = instance; + } + + inline int pkcsHasPassword( + CertSvcString filepath, + int *has_password) + { + return c_certsvc_pkcs12_has_password(filepath.privateHandler, has_password); + } + + inline int getPkcsPrivateKey( + CertSvcString pfxIdString, + char **buffer, + int *size) + { + int result = c_certsvc_pkcs12_private_key_load(pfxIdString.privateHandler, buffer); + if(result == CERTSVC_SUCCESS) + *size = strlen(*buffer); + return result; + } + + inline int getPkcsCertificateList( + CertSvcInstance &instance, + CertSvcString &pfxIdString, + CertSvcCertificateList *handler) + { + gchar **certs; + gsize i, ncerts; + std::vector certPtrVector; + std::vector listId; + int result; + + result = c_certsvc_pkcs12_load_certificates(pfxIdString.privateHandler, &certs, &ncerts); + if(result != CERTSVC_SUCCESS) + return result; + for(i = 0; i < ncerts; i++) { + ScopedCertCtx context(cert_svc_cert_context_init(), cert_svc_cert_context_final); + if(cert_svc_load_file_to_context(context.get(), certs[i]) != CERT_SVC_ERR_NO_ERROR) { + c_certsvc_pkcs12_free_certificates(certs); + return CERTSVC_IO_ERROR; + } + else + certPtrVector.push_back(CertificatePtr(new Certificate(*(context->certBuf)))); + } + c_certsvc_pkcs12_free_certificates(certs); + + FOREACH(it, certPtrVector) { + listId.push_back(addCert(*it)); + } + + int position = m_idListCounter++; + m_idListMap[position] = listId; + + handler->privateInstance = instance; + handler->privateHandler = position; + + return result; + } + + inline int pkcsDelete(CertSvcString pfxIdString) + { + return c_certsvc_pkcs12_delete(pfxIdString.privateHandler); + } + +private: + int m_certificateCounter; + std::map m_certificateMap; + + int m_idListCounter; + std::map > m_idListMap; + + int m_stringListCounter; + std::map > m_stringListMap; + + std::set m_allocatedStringSet; + + CertSvcCrlCacheWrite m_crlWrite; + CertSvcCrlCacheRead m_crlRead; + CertSvcCrlFree m_crlFree; +}; + +inline CertSvcInstanceImpl *impl(CertSvcInstance instance) { + return static_cast(instance.privatePtr); +} + +} // namespace anonymous + +int certsvc_instance_new(CertSvcInstance *instance) { + static int init = 1; + if (init) { + SSL_library_init(); // required by message verification + OpenSSL_add_all_digests(); + g_type_init(); // required by libsoup/ocsp + init = 0; + } + try { + instance->privatePtr = + reinterpret_cast(new CertSvcInstanceImpl); + if (instance->privatePtr) + return CERTSVC_SUCCESS; + } catch (std::bad_alloc &) { + return CERTSVC_BAD_ALLOC; + } catch (...) {} + return CERTSVC_FAIL; +} + +void certsvc_instance_reset(CertSvcInstance instance) { + impl(instance)->reset(); +} + +void certsvc_instance_free(CertSvcInstance instance) { + delete impl(instance); +} + +int certsvc_certificate_new_from_file( + CertSvcInstance instance, + const char *location, + CertSvcCertificate *certificate) +{ + try { + ScopedCertCtx context(cert_svc_cert_context_init(), + cert_svc_cert_context_final); + + int result = cert_svc_load_file_to_context(context.get(), location); + + switch(result) { + case CERT_SVC_ERR_INVALID_PARAMETER: return CERTSVC_WRONG_ARGUMENT; + case CERT_SVC_ERR_INVALID_OPERATION: return CERTSVC_FAIL; + case CERT_SVC_ERR_MEMORY_ALLOCATION: return CERTSVC_BAD_ALLOC; + default:; + } + + CertificatePtr cert(new Certificate(*(context->certBuf))); + + certificate->privateInstance = instance; + certificate->privateHandler = impl(instance)->addCert(cert); + + return CERTSVC_SUCCESS; + // TODO support for std exceptions + } catch (std::bad_alloc &) { + return CERTSVC_BAD_ALLOC; + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_certificate_new_from_memory( + CertSvcInstance instance, + const unsigned char *memory, + int len, + CertSvcCertificateForm form, + CertSvcCertificate *certificate) +{ + try { + Certificate::FormType formType; + std::string binary((char*)memory, len); + + if (CERTSVC_FORM_DER == form) { + formType = Certificate::FORM_DER; + } else { + formType = Certificate::FORM_BASE64; + } + + CertificatePtr cert(new Certificate(binary, formType)); + + certificate->privateInstance = instance; + certificate->privateHandler = impl(instance)->addCert(cert); + return CERTSVC_SUCCESS; + } catch (std::bad_alloc &) { + return CERTSVC_BAD_ALLOC; + } catch (...) {} + return CERTSVC_FAIL; +} + +void certsvc_certificate_free(CertSvcCertificate certificate) +{ + impl(certificate.privateInstance)->removeCert(certificate); +} + +int certsvc_certificate_save_file( + CertSvcCertificate certificate, + const char *location) +{ + return impl(certificate.privateInstance)->saveToFile(certificate, location); +} + +int certsvc_certificate_search( + CertSvcInstance instance, + CertSvcCertificateField field, + const char *value, + CertSvcCertificateList *handler) +{ + try { + return impl(instance)->certificateSearch(instance, field, value, handler); + } catch (std::bad_alloc &) { + return CERTSVC_BAD_ALLOC; + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_certificate_list_get_one( + CertSvcCertificateList handler, + int position, + CertSvcCertificate *certificate) +{ + return impl(handler.privateInstance)-> + getCertFromList(handler,position, certificate); +} + +int certsvc_certificate_list_get_length( + CertSvcCertificateList handler, + int *size) +{ + return impl(handler.privateInstance)->getCertListLen(handler, size); +} + +void certsvc_certificate_list_free(CertSvcCertificateList handler) +{ + impl(handler.privateInstance)->removeCertList(handler); +} + +int certsvc_certificate_is_signed_by( + CertSvcCertificate child, + CertSvcCertificate parent, + int *status) +{ + if (child.privateInstance.privatePtr == parent.privateInstance.privatePtr) { + return impl(child.privateInstance)->isSignedBy(child, parent, status); + } + return CERTSVC_WRONG_ARGUMENT; +} + +int certsvc_certificate_get_string_field( + CertSvcCertificate certificate, + CertSvcCertificateField field, + CertSvcString *buffer) +{ + try { + return impl(certificate.privateInstance)->getField(certificate, field, buffer); + } catch (std::bad_alloc &) { + return CERTSVC_BAD_ALLOC; + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_certificate_get_not_after( + CertSvcCertificate certificate, + time_t *result) +{ + try { + return impl(certificate.privateInstance)->getNotAfter(certificate, result); + } catch(...) {} + return CERTSVC_FAIL; +} + +int certsvc_certificate_get_not_before( + CertSvcCertificate certificate, + time_t *result) +{ + try { + return impl(certificate.privateInstance)->getNotBefore(certificate, result); + } catch(...) {} + return CERTSVC_FAIL; +} + +int certsvc_certificate_is_root_ca(CertSvcCertificate certificate, int *status) +{ + return impl(certificate.privateInstance)->isRootCA(certificate, status); +} + +int certsvc_certificate_get_crl_distribution_points( + CertSvcCertificate certificate, + CertSvcStringList *handler) +{ + try { + return impl(certificate.privateInstance)->getCrl(certificate, handler); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_string_list_get_one( + CertSvcStringList handler, + int position, + CertSvcString *buffer) +{ + try { + return impl(handler.privateInstance)->getStringFromList(handler, position, buffer); + } catch (std::bad_alloc &) { + return CERTSVC_BAD_ALLOC; + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_string_list_get_length( + CertSvcStringList handler, + int *size) +{ + return impl(handler.privateInstance)->getStringListLen(handler, size); +} + +void certsvc_string_list_free(CertSvcStringList handler) +{ + impl(handler.privateInstance)->removeStringList(handler); +} + +void certsvc_string_free(CertSvcString string) +{ + impl(string.privateInstance)->removeString(string); +} + +void certsvc_string_to_cstring( + CertSvcString string, + const char **buffer, + int *len) +{ + if (buffer) { + *buffer = string.privateHandler; + } + if (len) { + *len = string.privateLength; + } +} + +int certsvc_certificate_chain_sort( + CertSvcCertificate *certificate_array, + int size) +{ + try { + if (!certificate_array) { + return CERTSVC_WRONG_ARGUMENT; + } + return impl(certificate_array[0].privateInstance)-> + sortCollection(certificate_array, size); + } catch (std::bad_alloc &) { + return CERTSVC_BAD_ALLOC; + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_certificate_dup_x509(CertSvcCertificate certificate, X509 **cert) +{ + try { + return impl(certificate.privateInstance)->getX509Copy(certificate, cert); + } catch (...) {} + return CERTSVC_FAIL; +} + +void certsvc_certificate_free_x509(X509 *x509) +{ + X509_free(x509); +} + +int certsvc_ocsp_check( + CertSvcCertificate *chain, + int chain_size, + CertSvcCertificate *trusted, + int trusted_size, + const char *url, + int *status) +{ + try { + if (!chain || !trusted) { + return CERTSVC_WRONG_ARGUMENT; + } + return impl(chain[0].privateInstance)-> + ocspCheck(chain, + chain_size, + trusted, + trusted_size, + url, + status); + } catch (std::bad_alloc &) { + return CERTSVC_BAD_ALLOC; + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_message_verify( + CertSvcCertificate certificate, + CertSvcString message, + CertSvcString signature, + const char *algorithm, + int *status) +{ + try { + return impl(certificate.privateInstance)->verify( + certificate, + message, + signature, + algorithm, + status); + } catch(...) {} + return CERTSVC_FAIL; +} + +int certsvc_base64_encode(CertSvcString message, CertSvcString *base64) +{ + try { + return impl(message.privateInstance)->base64Encode(message, base64); + } catch(...) {} + return CERTSVC_FAIL; +} + +int certsvc_base64_decode(CertSvcString base64, CertSvcString *message) +{ + try { + return impl(base64.privateInstance)->base64Decode(base64, message); + } catch(...) {} + return CERTSVC_FAIL; +} + +int certsvc_string_new( + CertSvcInstance instance, + const char *url, + int size, + CertSvcString *output) +{ + try { + return impl(instance)->stringNew(instance, url, size, output); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_string_not_managed( + CertSvcInstance instance, + const char *url, + int size, + CertSvcString *output) +{ + if (!output) { + return CERTSVC_WRONG_ARGUMENT; + } + output->privateHandler = const_cast(url); + output->privateLength = size; + output->privateInstance = instance; + return CERTSVC_SUCCESS; +} + +void certsvc_crl_cache_functions( + CertSvcInstance instance, + CertSvcCrlCacheWrite writePtr, + CertSvcCrlCacheRead readPtr, + CertSvcCrlFree freePtr) +{ + impl(instance)->setCRLFunction(writePtr, readPtr, freePtr); +} + +int certsvc_crl_check( + CertSvcCertificate certificate, + CertSvcCertificate *trustedStore, + int storeSize, + int force, + int *status, + void *userParam) +{ + try { + return impl(certificate.privateInstance)->crlCheck( + certificate, + trustedStore, + storeSize, + force, + status, + userParam); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_certificate_verify( + CertSvcCertificate certificate, + CertSvcCertificate *trusted, + int trustedSize, + CertSvcCertificate *untrusted, + int untrustedSize, + int *status) +{ + try { + return impl(certificate.privateInstance)->certificateVerify( + certificate, + trusted, + trustedSize, + untrusted, + untrustedSize, + status); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_alias_exists(CertSvcInstance instance, + CertSvcString pfxIdString, + int *is_unique) +{ + try { + return impl(instance)->pkcsNameIsUnique(pfxIdString, is_unique); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_import_from_file(CertSvcInstance instance, + CertSvcString path, + CertSvcString password, + CertSvcString pfxIdString) +{ + try { + return impl(instance)->pkcsImport(path, password, pfxIdString); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_get_id_list( + CertSvcInstance instance, + CertSvcStringList *pfxIdStringList) +{ + try { + return impl(instance)->getPkcsIdList( + instance, + pfxIdStringList); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_has_password( + CertSvcInstance instance, + CertSvcString filepath, + int *has_password) +{ + try { + return impl(instance)->pkcsHasPassword( + filepath, + has_password); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_load_certificate_list( + CertSvcInstance instance, + CertSvcString pfxIdString, + CertSvcCertificateList *certificateList) +{ + try { + return impl(instance)->getPkcsCertificateList( + instance, + pfxIdString, + certificateList); + } catch (...) {} + return CERTSVC_FAIL; +} + +int certsvc_pkcs12_private_key_dup( + CertSvcInstance instance, + CertSvcString pfxIdString, + char **buffer, + int *size) +{ + try { + return impl(instance)->getPkcsPrivateKey(pfxIdString, buffer, size); + } catch (...) {} + return CERTSVC_FAIL; +} + +void certsvc_pkcs12_private_key_free( + char *buffer) +{ + delete[] buffer; +} + +int certsvc_pkcs12_delete( + CertSvcInstance instance, + CertSvcString pfxIdString) +{ + try { + return impl(instance)->pkcsDelete(pfxIdString); + } catch (...) {} + return CERTSVC_FAIL; +} diff --git a/vcore/src/vcore/pkcs12.c b/vcore/src/vcore/pkcs12.c new file mode 100644 index 0000000..7f0317e --- /dev/null +++ b/vcore/src/vcore/pkcs12.c @@ -0,0 +1,474 @@ +/** + * Copyright (c) 2011 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 pkcs12.h + * @author Jacek Migacz (j.migacz@samsung.com) + * @version 1.0 + * @brief PKCS#12 container manipulation routines. + */ +#define _GNU_SOURCE + +#include "pkcs12.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SYSCALL(call) while(((call) == -1) && (errno == EINTR)) + +#define CERTSVC_PKCS12_STORAGE_DIR "/opt/share/cert-svc/pkcs12" +#define CERTSVC_PKCS12_STORAGE_FILE "storage" +#define CERTSVC_PKCS12_STORAGE_PATH CERTSVC_PKCS12_STORAGE_DIR "/" CERTSVC_PKCS12_STORAGE_FILE + +static const char CERTSVC_PKCS12_STORAGE_KEY_PKEY[] = "pkey"; +static const char CERTSVC_PKCS12_STORAGE_KEY_CERTS[] = "certs"; +static const gchar CERTSVC_PKCS12_STORAGE_SEPARATOR = ';'; + +static gboolean keyfile_check(const char *pathname) { + int result; + if(access(pathname, F_OK | R_OK | W_OK) == 0) + return TRUE; + SYSCALL(result = creat(pathname, S_IRUSR | S_IWUSR)); + return (result != -1) ? TRUE : FALSE; +} + +static GKeyFile *keyfile_load(const char *pathname) { + GKeyFile *keyfile; + GError *error; + + if(!keyfile_check(pathname)) + return NULL; + keyfile = g_key_file_new(); + error = NULL; + if(!g_key_file_load_from_file(keyfile, pathname, G_KEY_FILE_KEEP_COMMENTS, &error)) { + g_key_file_free(keyfile); + return NULL; + } + return keyfile; +} + +static int generate_random_filepath(char **filepath) { + int generator; + int64_t random; + SHA_CTX ctx; + unsigned char d[SHA_DIGEST_LENGTH]; + int result; + + if(!filepath) + return CERTSVC_WRONG_ARGUMENT; + + SYSCALL(generator = open("/dev/urandom", O_RDONLY)); + if(generator == -1) + return CERTSVC_FAIL; + SYSCALL(result = read(generator, &random, sizeof(random))); + if(result == -1) { + SYSCALL(close(generator)); + return CERTSVC_FAIL; + } + SYSCALL(result = close(generator)); + if(result == -1) + return CERTSVC_FAIL; + + SHA1_Init(&ctx); + SHA1_Update(&ctx, &random, sizeof(random)); + SHA1_Final(d, &ctx); + + result = asprintf(filepath, "%s/" \ + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \ + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + CERTSVC_PKCS12_STORAGE_DIR, + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], + d[10], d[11], d[12], d[13], d[14], d[15], d[16], d[17], d[18], d[19]); + return (result != -1) ? CERTSVC_SUCCESS : CERTSVC_BAD_ALLOC; +} + +static int unique_filename(char **filepath, gboolean with_secure_storage) { + const unsigned attempts = 0xFFU; + unsigned trial; + int result; + ssm_file_info_t sfi; + gboolean exists; + + trial = 0U; + try_again: + ++trial; + result = generate_random_filepath(filepath); + if(result != CERTSVC_SUCCESS) + return result; + if(with_secure_storage) + exists = (access(*filepath, F_OK) == 0 || ssm_getinfo(*filepath, &sfi, SSM_FLAG_DATA, NULL) == 0); + else + exists = (access(*filepath, F_OK) == 0); + if(exists) { + free(*filepath); + if(trial + 1 > attempts) + return CERTSVC_FAIL; + else + goto try_again; + } + return CERTSVC_SUCCESS; +} + +static char *bare_filename(char *filepath) { + char *needle; + if(!filepath) + return NULL; + needle = strrchr(filepath, '/'); + if(!needle) + return NULL; + return *(++needle) ? needle : NULL; +} + +int c_certsvc_pkcs12_alias_exists(const gchar *alias, gboolean *exists) { + GKeyFile *keyfile; + + if(exists == NULL) + return CERTSVC_WRONG_ARGUMENT; + keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); + if(!keyfile) + return CERTSVC_IO_ERROR; + *exists = g_key_file_has_group(keyfile, alias); + g_key_file_free(keyfile); + return CERTSVC_SUCCESS; +} + +int c_certsvc_pkcs12_import(const char *path, const char *password, const gchar *alias) { + int exists; + FILE *stream; + PKCS12 *container; + EVP_PKEY *key; + X509 *cert; + STACK_OF(X509) *certv; + int nicerts; + char *unique; + int result; + struct stat st; + int wr_res; + GKeyFile *keyfile; + gchar *bare; + gchar *pkvalue; + gchar **cvaluev; + gsize i, n; + gchar *data; + gsize length; + + certv = NULL; + if(!alias || strlen(alias) < 1) + return CERTSVC_WRONG_ARGUMENT; + result = c_certsvc_pkcs12_alias_exists(alias, &exists); + if(result != CERTSVC_SUCCESS) + return result; + if(exists == TRUE) + return CERTSVC_DUPLICATED_ALIAS; + + keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); + if(!keyfile) + return CERTSVC_IO_ERROR; + if(stat(CERTSVC_PKCS12_STORAGE_PATH, &st) == -1) { + if(mkdir(CERTSVC_PKCS12_STORAGE_PATH, S_IRWXU | S_IRWXG | S_IRWXO) == -1) { + result = CERTSVC_FAIL; + goto free_keyfile; + } + } + + if((stream = fopen(path, "rb")) == NULL) { + result = CERTSVC_IO_ERROR; + goto free_keyfile; + } + container = d2i_PKCS12_fp(stream, NULL); + fclose(stream); + if(container == NULL) { + result = CERTSVC_FAIL; + goto free_keyfile; + } + result = PKCS12_parse(container, password, &key, &cert, &certv); + PKCS12_free(container); + if(result == 0) { + result = CERTSVC_FAIL; + goto free_keyfile; + } + nicerts = certv ? sk_X509_num(certv) : 0; + cvaluev = (gchar **)calloc(1 + nicerts, sizeof(gchar *)); + n = 0; + + result = unique_filename(&unique, TRUE); + if(result != CERTSVC_SUCCESS) + goto clean_cert_chain_and_pkey; + if((stream = fopen(unique, "w")) == NULL) { + free(unique); + result = CERTSVC_IO_ERROR; + goto clean_cert_chain_and_pkey; + } + result = PEM_write_PrivateKey(stream, key, NULL, NULL, 0, NULL, NULL); + fclose(stream); + if(result == 0) { + result = CERTSVC_FAIL; + goto clean_cert_chain_and_pkey; + } + wr_res = ssm_write_file(unique, SSM_FLAG_DATA, NULL); + if(wr_res != 0) { + free(unique); + result = CERTSVC_FAIL; + goto clean_cert_chain_and_pkey; + } + bare = bare_filename(unique); + if(bare) { + pkvalue = g_strdup(bare); + g_key_file_set_string(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_PKEY, pkvalue); + } + free(unique); + result = unique_filename(&unique, FALSE); + if(result != CERTSVC_SUCCESS) + goto clean_cert_chain_and_pkey; + if((stream = fopen(unique, "w")) == NULL) { + free(unique); + result = CERTSVC_IO_ERROR; + goto clean_cert_chain_and_pkey; + } + result = PEM_write_X509_AUX(stream, cert); + fclose(stream); + if(result == 0) { + result = CERTSVC_FAIL; + goto clean_cert_chain_and_pkey; + } + bare = bare_filename(unique); + if(bare) + cvaluev[n++] = g_strdup(bare); + free(unique); + for(i = 0; i < nicerts; i++) { + result = unique_filename(&unique, FALSE); + if(result != CERTSVC_SUCCESS) + goto clean_cert_chain_and_pkey; + if((stream = fopen(unique, "w")) == NULL) { + free(unique); + result = CERTSVC_IO_ERROR; + goto clean_cert_chain_and_pkey; + } + result = PEM_write_X509_AUX(stream, sk_X509_value(certv, i)); + fclose(stream); + if(result == 0) { + result = CERTSVC_FAIL; + goto clean_cert_chain_and_pkey; + } + bare = bare_filename(unique); + if(bare) + cvaluev[n++] = g_strdup(bare); + free(unique); + } + g_key_file_set_list_separator(keyfile, CERTSVC_PKCS12_STORAGE_SEPARATOR); + g_key_file_set_string_list(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_CERTS, (gchar *const *)cvaluev, n + 1); + data = g_key_file_to_data(keyfile, &length, NULL); + if(data == NULL) { + result = CERTSVC_BAD_ALLOC; + goto clean_cert_chain_and_pkey; + } + if(!g_file_set_contents(CERTSVC_PKCS12_STORAGE_PATH, data, length, NULL)) { + result = CERTSVC_IO_ERROR; + goto free_data; + } + result = CERTSVC_SUCCESS; + free_data: + g_free(data); + clean_cert_chain_and_pkey: + EVP_PKEY_free(key); + X509_free(cert); + sk_X509_free(certv); + free(pkvalue); + for(i = 0; i < n; i++) { + g_free(cvaluev[i]); + } + free(cvaluev); + free_keyfile: + g_key_file_free(keyfile); + return result; +} + +int c_certsvc_pkcs12_aliases_load(gchar ***aliases, gsize *naliases) { + GKeyFile *keyfile; + + keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); + if(!keyfile) + return CERTSVC_IO_ERROR; + *aliases = g_key_file_get_groups(keyfile, naliases); + g_key_file_free(keyfile); + return CERTSVC_SUCCESS; +} + +void c_certsvc_pkcs12_aliases_free(gchar **aliases) { + g_strfreev(aliases); +} + +int c_certsvc_pkcs12_has_password(const char *filepath, gboolean *passworded) { + FILE *stream; + EVP_PKEY *pkey; + X509 *cert; + PKCS12 *container; + int result; + + if(passworded == NULL) + return CERTSVC_WRONG_ARGUMENT; + if((stream = fopen(filepath, "rb")) == NULL) + return CERTSVC_IO_ERROR; + container = d2i_PKCS12_fp(stream, NULL); + fclose(stream); + if(container == NULL) + return CERTSVC_FAIL; + result = PKCS12_parse(container, NULL, &pkey, &cert, NULL); + PKCS12_free(container); + if(result == 1) { + EVP_PKEY_free(pkey); + X509_free(cert); + *passworded = FALSE; + return CERTSVC_SUCCESS; + } + else { + if(ERR_GET_REASON(ERR_peek_last_error()) == PKCS12_R_MAC_VERIFY_FAILURE) { + *passworded = TRUE; + return CERTSVC_SUCCESS; + } + else + return CERTSVC_FAIL; + } +} + +int c_certsvc_pkcs12_load_certificates(const gchar *alias, gchar ***certs, gsize *ncerts) { + GKeyFile *keyfile; + gchar **barev; + gsize i; + keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); + if(!keyfile) + return CERTSVC_IO_ERROR; + g_key_file_set_list_separator(keyfile, CERTSVC_PKCS12_STORAGE_SEPARATOR); + barev = g_key_file_get_string_list(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_CERTS, ncerts, NULL); + *certs = g_malloc((*ncerts + 1) * sizeof(gchar *)); + for(i = 0; i < *ncerts; i++) + *certs[i] = g_strdup_printf("%s/%s", CERTSVC_PKCS12_STORAGE_DIR, barev[i]); + (*certs)[*ncerts] = NULL; + g_strfreev(barev); + g_key_file_free(keyfile); + return CERTSVC_SUCCESS; +} + +void c_certsvc_pkcs12_free_certificates(gchar **certs) { + gsize i = 0; + if(certs == NULL) + return; + while(certs[i]) + g_free(certs[i++]); + g_free(certs); +} + +int c_certsvc_pkcs12_private_key_load(const gchar *alias, char **buffer) { + GKeyFile *keyfile; + gchar *pkey; + GError *error; + ssm_file_info_t sfi; + size_t readlen; + char *spkp; + int result; + + if(!buffer) + return CERTSVC_WRONG_ARGUMENT; + keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); + if(!keyfile) + return CERTSVC_IO_ERROR; + error = NULL; + result = CERTSVC_SUCCESS; + pkey = g_key_file_get_string(keyfile, alias, CERTSVC_PKCS12_STORAGE_KEY_PKEY, &error); + if(error && error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) + result = CERTSVC_SUCCESS; + else if(error) + result = CERTSVC_FAIL; + else { + if(asprintf(&spkp, "%s/%s", CERTSVC_PKCS12_STORAGE_DIR, pkey) == -1) { + spkp = NULL; + result = CERTSVC_BAD_ALLOC; + } + else if(ssm_getinfo(spkp, &sfi, SSM_FLAG_DATA, NULL) == 0) { + if((*buffer = malloc(sfi.originSize))) { + if(ssm_read(spkp, *buffer, sfi.originSize, &readlen, SSM_FLAG_DATA, NULL) != 0) { + c_certsvc_pkcs12_private_key_free(buffer); + result = CERTSVC_FAIL; + } + } + else + result = CERTSVC_BAD_ALLOC; + } + free(spkp); + g_free(pkey); + } + g_key_file_free(keyfile); + return result; +} + +void c_certsvc_pkcs12_private_key_free(char *buffer) { + free(buffer); +} + +int c_certsvc_pkcs12_delete(const gchar *alias) { + gchar **certs; + gsize ncerts; + char *pkey; + int result; + GKeyFile *keyfile; + gchar *data; + gsize i, length; + + result = c_certsvc_pkcs12_load_certificates(alias, &certs, &ncerts); + if(result != CERTSVC_SUCCESS) + goto load_certificates_failed; + result = c_certsvc_pkcs12_private_key_load(alias, &pkey); + if(result != CERTSVC_SUCCESS) + goto private_key_load_failed; + keyfile = keyfile_load(CERTSVC_PKCS12_STORAGE_PATH); + if(!keyfile) { + result = CERTSVC_IO_ERROR; + goto keyfile_load_failed; + } + if(g_key_file_remove_group(keyfile, alias, NULL)) { + data = g_key_file_to_data(keyfile, &length, NULL); + if(data == NULL) { + result = CERTSVC_BAD_ALLOC; + goto keyfile_free; + } + if(!g_file_set_contents(CERTSVC_PKCS12_STORAGE_PATH, data, length, NULL)) { + result = CERTSVC_IO_ERROR; + goto data_free; + } + } + for(i = 0; i < ncerts; i++) + unlink(certs[i]); + ssm_delete_file(pkey, SSM_FLAG_DATA, NULL); + data_free: + g_free(data); + keyfile_free: + g_key_file_free(keyfile); + keyfile_load_failed: + c_certsvc_pkcs12_private_key_free(pkey); + private_key_load_failed: + c_certsvc_pkcs12_free_certificates(certs); + load_certificates_failed: + return result; +} diff --git a/vcore/src/vcore/pkcs12.h b/vcore/src/vcore/pkcs12.h new file mode 100644 index 0000000..ddea458 --- /dev/null +++ b/vcore/src/vcore/pkcs12.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2011 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 pkcs12.c + * @author Jacek Migacz (j.migacz@samsung.com) + * @version 1.0 + * @brief PKCS#12 container manipulation routines. + */ +#ifndef _PKCS12_H_ +#define _PKCS12_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int c_certsvc_pkcs12_alias_exists(const gchar *alias, gboolean *exists); +int c_certsvc_pkcs12_import(const char *path, const char *password, const gchar *alias); +int c_certsvc_pkcs12_aliases_load(gchar ***aliases, gsize *naliases); +void c_certsvc_pkcs12_aliases_free(gchar **aliases); +int c_certsvc_pkcs12_has_password(const char *filepath, gboolean *passworded); +int c_certsvc_pkcs12_load_certificates(const gchar *alias, gchar ***certificates, gsize *ncertificates); +void c_certsvc_pkcs12_free_certificates(gchar **certs); +int c_certsvc_pkcs12_private_key_load(const gchar *alias, char **pkey); +void c_certsvc_pkcs12_private_key_free(char *buffer); +/* +int c_certsvc_pkcs12_certificate_email_load(const gchar *alias, char **buffer, int *size); +void c_certsvc_pkcs12_certificate_email_free(char *buffer); +*/ +int c_certsvc_pkcs12_delete(const gchar *alias); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vcore/src/vcore/scoped_gpointer.h b/vcore/src/vcore/scoped_gpointer.h new file mode 100644 index 0000000..78772df --- /dev/null +++ b/vcore/src/vcore/scoped_gpointer.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011 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 scoped_fclose.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped fclose RAII + */ +#ifndef WRT_ENGINE_SRC_COMMON_SCOPED_GPOINTER_H +#define WRT_ENGINE_SRC_COMMON_SCOPED_GPOINTER_H + +#include +#include + +#include +#include + +namespace WRT { +struct ScopedGPointerPolicy +{ + typedef gpointer Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type pointer) + { + if (pointer != NULL) { + g_object_unref(pointer); + } + } +}; + +template +class ScopedGPointer : public DPL::ScopedResource +{ + typedef ScopedGPointerPolicy Policy; + typedef DPL::ScopedResource BaseType; + + public: + explicit ScopedGPointer(typename Policy::Type pointer = + Policy::NullValue()) : + BaseType(pointer) + { + } + + Class *operator->() const throw() + { + Assert(this->m_value != Policy::NullValue() && + "Dereference of scoped NULL pointer!"); + return static_cast(this->m_value); + } + + Class & operator *() const throw() + { + Assert(this->m_value != Policy::NullValue() && + "Dereference of scoped NULL pointer!"); + return *static_cast(this->m_value); + } +}; +} // namespace WRT + +#endif // WRT_ENGINE_SRC_COMMON_SCOPED_GPOINTER_H