From 8bc346d139c22bedf609a4d553d947e630dc4524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Soutad=C3=A9?= Date: Sat, 21 Aug 2021 20:46:09 +0200 Subject: [PATCH] Add fetchLicenseServiceCertificate() because not all signing certificates (to be included into rights.xml) are the same than the one fetched at authentication --- include/libgourou.h | 2 ++ include/user.h | 8 ++++-- src/fulfillment_item.cpp | 25 +++++++++++++---- src/libgourou.cpp | 59 ++++++++++++++++++++++++++++++++++++---- src/user.cpp | 20 ++++++++++++-- 5 files changed, 98 insertions(+), 16 deletions(-) diff --git a/include/libgourou.h b/include/libgourou.h index 0d62700..8c6e957 100644 --- a/include/libgourou.h +++ b/include/libgourou.h @@ -194,6 +194,8 @@ namespace gourou void buildActivateReq(pugi::xml_document& activateReq); ByteArray sendFulfillRequest(const pugi::xml_document& document, const std::string& url); void buildSignInRequest(pugi::xml_document& signInRequest, const std::string& adobeID, const std::string& adobePassword, const std::string& authenticationCertificate); + void fetchLicenseServiceCertificate(const std::string& licenseURL, + const std::string& operatorURL); }; } diff --git a/include/user.h b/include/user.h index 625862e..4966dc5 100644 --- a/include/user.h +++ b/include/user.h @@ -14,13 +14,15 @@ GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with libgourou. If not, see . + along with libgourou. If not, see . */ #ifndef _USER_H_ #define _USER_H_ #include +#include + #include "bytearray.h" #include @@ -46,7 +48,7 @@ namespace gourou std::string& getDeviceFingerprint(); std::string& getUsername(); std::string& getLoginMethod(); - std::string& getCertificate(); + std::string getLicenseServiceCertificate(std::string url); std::string& getAuthenticationCertificate(); std::string& getPrivateLicenseKey(); @@ -95,7 +97,7 @@ namespace gourou std::string deviceFingerprint; std::string username; std::string loginMethod; - std::string certificate; + std::map licenseServiceCertificates; std::string authenticationCertificate; std::string privateLicenseKey; diff --git a/src/fulfillment_item.cpp b/src/fulfillment_item.cpp index e69e446..f290d4f 100644 --- a/src/fulfillment_item.cpp +++ b/src/fulfillment_item.cpp @@ -36,6 +36,12 @@ namespace gourou if (downloadURL == "") EXCEPTION(FFI_INVALID_FULFILLMENT_DATA, "No download URL in document"); + node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/resource").node(); + resource = node.first_child().value(); + + if (resource == "") + EXCEPTION(FFI_INVALID_FULFILLMENT_DATA, "No resource in document"); + pugi::xml_node licenseToken = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken").node(); if (!licenseToken) @@ -55,12 +61,14 @@ namespace gourou pugi::xml_node newLicenseToken = root.append_copy(licenseToken); if (!newLicenseToken.attribute("xmlns")) newLicenseToken.append_attribute("xmlns") = ADOBE_ADEPT_NS; - - pugi::xml_node licenseServiceInfo = root.append_child("licenseServiceInfo"); - licenseServiceInfo.append_attribute("xmlns") = ADOBE_ADEPT_NS; - licenseServiceInfo.append_copy(licenseToken.select_node("licenseURL").node()); - pugi::xml_node certificate = licenseServiceInfo.append_child("certificate"); - certificate.append_child(pugi::node_pcdata).set_value(user->getCertificate().c_str()); + + pugi::xml_node licenseServiceInfo = root.append_child("adept:licenseServiceInfo"); + pugi::xml_node licenseURL = licenseToken.select_node("licenseURL").node(); + licenseURL.set_name("adept:licenseURL"); + licenseServiceInfo.append_copy(licenseURL); + pugi::xml_node certificate = licenseServiceInfo.append_child("adept:certificate"); + std::string certificateValue = user->getLicenseServiceCertificate(licenseURL.first_child().value()); + certificate.append_child(pugi::node_pcdata).set_value(certificateValue.c_str()); } std::string FulfillmentItem::getMetadata(std::string name) @@ -88,4 +96,9 @@ namespace gourou { return downloadURL; } + + std::string FulfillmentItem::getResource() + { + return resource; + } } diff --git a/src/libgourou.cpp b/src/libgourou.cpp index 65d961d..d86c4aa 100644 --- a/src/libgourou.cpp +++ b/src/libgourou.cpp @@ -33,6 +33,7 @@ #define ASN_TEXT 0x04 #define ASN_ATTRIBUTE 0x05 + namespace gourou { GOUROU_LOG_LEVEL logLevel = WARN; @@ -453,6 +454,49 @@ namespace gourou appendTextElem(activationToken, "adept:device", user->getDeviceUUID()); } + void DRMProcessor::fetchLicenseServiceCertificate(const std::string& licenseURL, + const std::string& operatorURL) + { + if (user->getLicenseServiceCertificate(licenseURL) != "") + return; + + std::string licenseServiceInfoReq = operatorURL + "/LicenseServiceInfo?licenseURL=" + licenseURL; + + ByteArray replyData; + replyData = sendRequest(licenseServiceInfoReq); + + pugi::xml_document licenseServicesDoc; + licenseServicesDoc.load_buffer(replyData.data(), replyData.length()); + + // Add new license certificate + pugi::xml_document activationDoc; + user->readActivation(activationDoc); + + pugi::xml_node root; + pugi::xpath_node xpathRes = activationDoc.select_node("//adept:licenseServices"); + + // Create adept:licenseServices if it doesn't exists + if (!xpathRes) + { + xpathRes = activationDoc.select_node("/activationInfo"); + root = xpathRes.node(); + root = root.append_child("adept:licenseServices"); + root.append_attribute("xmlns:adept") = ADOBE_ADEPT_NS; + } + else + root = xpathRes.node(); + + root = root.append_child("adept:licenseServiceInfo"); + + std::string certificate = extractTextElem(licenseServicesDoc, + "/licenseServiceInfo/certificate"); + + appendTextElem(root, "adept:licenseURL", licenseURL); + appendTextElem(root, "adept:certificate", certificate); + + user->updateActivationFile(activationDoc); + } + FulfillmentItem* DRMProcessor::fulfill(const std::string& ACSMFile) { if (!user->getPKCS12().length()) @@ -495,15 +539,16 @@ namespace gourou EXCEPTION(FF_NO_OPERATOR_URL, "OperatorURL not found in ACSM document"); std::string operatorURL = node.node().first_child().value(); - operatorURL = trim(operatorURL) + "/Fulfill"; + operatorURL = trim(operatorURL); + std::string fulfillURL = operatorURL + "/Fulfill"; - operatorAuth(operatorURL); + operatorAuth(fulfillURL); ByteArray replyData; try { - replyData = sendRequest(fulfillReq, operatorURL); + replyData = sendRequest(fulfillReq, fulfillURL); } catch (gourou::Exception& e) { @@ -515,8 +560,8 @@ namespace gourou if (e.getErrorCode() == GOUROU_ADEPT_ERROR && errorMsg.find("E_ADEPT_DISTRIBUTOR_AUTH") != std::string::npos) { - doOperatorAuth(operatorURL); - replyData = sendRequest(fulfillReq, operatorURL); + doOperatorAuth(fulfillURL); + replyData = sendRequest(fulfillReq, fulfillURL); } else { @@ -527,7 +572,11 @@ namespace gourou pugi::xml_document fulfillReply; fulfillReply.load_string((const char*)replyData.data()); + + std::string licenseURL = extractTextElem(fulfillReply, "//licenseToken/licenseURL"); + fetchLicenseServiceCertificate(licenseURL, operatorURL); + return new FulfillmentItem(fulfillReply, user); } diff --git a/src/user.cpp b/src/user.cpp index b90e3e8..4d7817b 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -48,7 +48,6 @@ namespace gourou { uuid = gourou::extractTextElem(activationDoc, "//adept:user", throwOnNull); deviceUUID = gourou::extractTextElem(activationDoc, "//device", throwOnNull); deviceFingerprint = gourou::extractTextElem(activationDoc, "//fingerprint", throwOnNull); - certificate = gourou::extractTextElem(activationDoc, "//adept:certificate", throwOnNull); authenticationCertificate = gourou::extractTextElem(activationDoc, "//adept:authenticationCertificate", throwOnNull); privateLicenseKey = gourou::extractTextElem(activationDoc, "//adept:privateLicenseKey", throwOnNull); username = gourou::extractTextElem(activationDoc, "//adept:username", throwOnNull); @@ -61,6 +60,15 @@ namespace gourou { if (throwOnNull) EXCEPTION(USER_INVALID_ACTIVATION_FILE, "Invalid activation file"); } + + pugi::xpath_node_set nodeSet = activationDoc.select_nodes("//adept:licenseServices/adept:licenseServiceInfo"); + for (pugi::xpath_node_set::const_iterator it = nodeSet.begin(); + it != nodeSet.end(); ++it) + { + std::string url = gourou::extractTextElem(it->node(), "adept:licenseURL"); + std::string certificate = gourou::extractTextElem(it->node(), "adept:certificate"); + licenseServiceCertificates[url] = certificate; + } } catch(gourou::Exception& e) { @@ -74,7 +82,6 @@ namespace gourou { std::string& User::getDeviceFingerprint() { return deviceFingerprint; } std::string& User::getUsername() { return username; } std::string& User::getLoginMethod() { return loginMethod; } - std::string& User::getCertificate() { return certificate; } std::string& User::getAuthenticationCertificate() { return authenticationCertificate; } std::string& User::getPrivateLicenseKey() { return privateLicenseKey; } @@ -200,4 +207,13 @@ namespace gourou { return user; } + + std::string User::getLicenseServiceCertificate(std::string url) + { + if (licenseServiceCertificates.count(trim(url))) + return licenseServiceCertificates[trim(url)]; + + return ""; + } + }