Add proof of private key challenge
Change-Id: Ic48b65c550603656c962e3c251f4dac1759cb4a1
diff --git a/src/challenge-module/challenge-credential.cpp b/src/challenge-module/challenge-credential.cpp
index 15d8721..08131c1 100644
--- a/src/challenge-module/challenge-credential.cpp
+++ b/src/challenge-module/challenge-credential.cpp
@@ -36,7 +36,7 @@
const std::string ChallengeCredential::FAILURE_INVALID_FORMAT_SELF_SIGNED = "failure-cannot-parse-self-signed";
const std::string ChallengeCredential::FAILURE_INVALID_CREDENTIAL = "failure-invalid-credential";
const std::string ChallengeCredential::JSON_CREDENTIAL_CERT = "issued-cert";
-const std::string ChallengeCredential::JSON_CREDENTIAL_SELF = "self-signed";
+const std::string ChallengeCredential::JSON_PROOF_OF_PRIVATE_KEY = "proof-of-private-key";
ChallengeCredential::ChallengeCredential(const std::string& configPath)
: ChallengeModule("Credential")
@@ -102,7 +102,7 @@
return;
}
}
- else if (readString(elements[i]) == JSON_CREDENTIAL_SELF) {
+ else if (readString(elements[i]) == JSON_PROOF_OF_PRIVATE_KEY) {
std::istringstream ss(readString(params.elements()[i + 1]));
selfSigned = io::load<security::v2::Certificate>(ss);
if (selfSigned == nullptr) {
@@ -148,7 +148,7 @@
JsonSection result;
if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
result.put(JSON_CREDENTIAL_CERT, "Please_copy_anchor_signed_cert_here");
- result.put(JSON_CREDENTIAL_SELF, "Please_copy_key_signed_request_id_data_here");
+ result.put(JSON_PROOF_OF_PRIVATE_KEY, "Please_copy_key_signed_request_id_data_here");
}
else {
_LOG_ERROR("Client's status and challenge status are wrong");
@@ -162,7 +162,7 @@
JsonSection result;
if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
result.put(JSON_CREDENTIAL_CERT, params.get(JSON_CREDENTIAL_CERT, ""));
- result.put(JSON_CREDENTIAL_SELF, params.get(JSON_CREDENTIAL_SELF, ""));
+ result.put(JSON_PROOF_OF_PRIVATE_KEY, params.get(JSON_PROOF_OF_PRIVATE_KEY, ""));
}
else {
_LOG_ERROR("Client's status and challenge status are wrong");
@@ -178,8 +178,8 @@
request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
request.push_back(makeStringBlock(tlv_parameter_key, JSON_CREDENTIAL_CERT));
request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_CREDENTIAL_CERT, "")));
- request.push_back(makeStringBlock(tlv_parameter_key, JSON_CREDENTIAL_SELF));
- request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_CREDENTIAL_SELF, "")));
+ request.push_back(makeStringBlock(tlv_parameter_key, JSON_PROOF_OF_PRIVATE_KEY));
+ request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_PROOF_OF_PRIVATE_KEY, "")));
}
else {
_LOG_ERROR("Client's status and challenge status are wrong");
diff --git a/src/challenge-module/challenge-credential.hpp b/src/challenge-module/challenge-credential.hpp
index bf53175..ad2b197 100644
--- a/src/challenge-module/challenge-credential.hpp
+++ b/src/challenge-module/challenge-credential.hpp
@@ -74,7 +74,7 @@
static const std::string FAILURE_INVALID_FORMAT_CREDENTIAL;
static const std::string FAILURE_INVALID_FORMAT_SELF_SIGNED;
static const std::string JSON_CREDENTIAL_CERT;
- static const std::string JSON_CREDENTIAL_SELF;
+ static const std::string JSON_PROOF_OF_PRIVATE_KEY;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
std::list<security::v2::Certificate> m_trustAnchors;
diff --git a/src/challenge-module/challenge-private-key.cpp b/src/challenge-module/challenge-private-key.cpp
new file mode 100644
index 0000000..0b77af9
--- /dev/null
+++ b/src/challenge-module/challenge-private-key.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#include "challenge-private-key.hpp"
+
+#include <iostream>
+#include <ndn-cxx/security/verification-helpers.hpp>
+#include <ndn-cxx/util/io.hpp>
+
+#include "../logging.hpp"
+
+namespace ndn {
+namespace ndncert {
+
+_LOG_INIT(ndncert.ChallengePrivateKey);
+
+NDNCERT_REGISTER_CHALLENGE(ChallengePrivateKey, "Private");
+
+const std::string ChallengePrivateKey::FAILURE_INVALID_REQUEST_TYPE = "failure-invalid-request-type";
+const std::string ChallengePrivateKey::FAILURE_INVALID_FORMAT_SELF_SIGNED = "failure-cannot-parse-self-signed";
+const std::string ChallengePrivateKey::FAILURE_INVALID_CREDENTIAL = "failure-invalid-credential";
+const std::string ChallengePrivateKey::JSON_PROOF_OF_PRIVATE_KEY = "proof-of-private-key";
+
+ChallengePrivateKey::ChallengePrivateKey()
+ : ChallengeModule("PrivateKey")
+{
+}
+
+// For CA
+void
+ChallengePrivateKey::handleChallengeRequest(const Block& params, CertificateRequest& request)
+{
+ if (request.m_requestType == REQUEST_TYPE_NEW) {
+ _LOG_TRACE("Cannot use this private key challenge for new certificate request");
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = FAILURE_INVALID_REQUEST_TYPE;
+ updateRequestOnChallengeEnd(request);
+ }
+ params.parse();
+ shared_ptr<security::v2::Certificate> selfSigned;
+ auto& elements = params.elements();
+ for (size_t i = 0; i < elements.size(); i++) {
+ if (elements[i].type() == tlv_parameter_key) {
+ if (readString(elements[i]) == JSON_PROOF_OF_PRIVATE_KEY) {
+ std::istringstream ss(readString(params.elements()[i + 1]));
+ selfSigned = io::load<security::v2::Certificate>(ss);
+ if (selfSigned == nullptr) {
+ _LOG_ERROR("Cannot load credential parameter: cert");
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = FAILURE_INVALID_FORMAT_SELF_SIGNED;
+ updateRequestOnChallengeEnd(request);
+ return;
+ }
+ }
+ else {
+ continue;
+ }
+ }
+ }
+
+ // verify the credential and the self-signed cert
+ if (security::verifySignature(*selfSigned, request.m_cert) &&
+ readString(selfSigned->getContent()) == request.m_requestId) {
+ request.m_status = STATUS_PENDING;
+ request.m_challengeStatus = CHALLENGE_STATUS_SUCCESS;
+ updateRequestOnChallengeEnd(request);
+ return;
+ }
+
+ _LOG_TRACE("Cannot verify the credential + self-signed Data + data content");
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = FAILURE_INVALID_CREDENTIAL;
+ updateRequestOnChallengeEnd(request);
+}
+
+// For Client
+JsonSection
+ChallengePrivateKey::getRequirementForChallenge(int status, const std::string& challengeStatus)
+{
+ JsonSection result;
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ result.put(JSON_PROOF_OF_PRIVATE_KEY, "Please_copy_key_signed_request_id_data_here");
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
+ return result;
+}
+
+JsonSection
+ChallengePrivateKey::genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params)
+{
+ JsonSection result;
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ result.put(JSON_PROOF_OF_PRIVATE_KEY, params.get(JSON_PROOF_OF_PRIVATE_KEY, ""));
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
+ return result;
+}
+
+Block
+ChallengePrivateKey::genChallengeRequestTLV(int status, const std::string& challengeStatus, const JsonSection& params)
+{
+ Block request = makeEmptyBlock(tlv_encrypted_payload);
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
+ request.push_back(makeStringBlock(tlv_parameter_key, JSON_PROOF_OF_PRIVATE_KEY));
+ request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_PROOF_OF_PRIVATE_KEY, "")));
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
+ request.encode();
+ return request;
+}
+} // namespace ndncert
+} // namespace ndn
diff --git a/src/challenge-module/challenge-private-key.hpp b/src/challenge-module/challenge-private-key.hpp
new file mode 100644
index 0000000..8e78d5a
--- /dev/null
+++ b/src/challenge-module/challenge-private-key.hpp
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#ifndef NDNCERT_CHALLENGE_PRIVATE_KEY_HPP
+#define NDNCERT_CHALLENGE_PRIVATE_KEY_HPP
+
+#include "../challenge-module.hpp"
+
+namespace ndn {
+namespace ndncert {
+
+/**
+ * @brief Private Key based challenge (for renewal and revocation)
+ *
+ * Once the requester could proof his/her possession of the private key corresponds to
+ * the current CA's previous issued certificate, the requester could finish the challenge.
+ *
+ * The requester needs to provide the proof of the possession the private for the certificate
+ * for the previous cerificate. The challenge require the requester to a BASE64 Data packet
+ * signed by the credential pub key and whose content is the request id.
+ *
+ * The main process of this challenge module is:
+ * 1. The requester sign a Data packet which content is the request id.
+ * 2. The challenge module will verify the signature of the credential.
+ *
+ * Failure info when application fails:
+ * FAILURE_INVALID_CREDENTIAL: When the signature cannot be validated.
+ * FAILURE_INVALID_FORMAT: When the credential format is wrong.
+ */
+class ChallengePrivateKey : public ChallengeModule
+{
+public:
+ ChallengePrivateKey();
+
+ // For CA
+ void
+ handleChallengeRequest(const Block& params, CertificateRequest& request) override;
+
+ // For Client
+ JsonSection
+ getRequirementForChallenge(int status, const std::string& challengeStatus) override;
+
+ JsonSection
+ genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params) override;
+
+ Block
+ genChallengeRequestTLV(int status, const std::string& challengeStatus, const JsonSection& params) override;
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ static const std::string FAILURE_INVALID_REQUEST_TYPE;
+ static const std::string FAILURE_INVALID_CREDENTIAL;
+ static const std::string FAILURE_INVALID_FORMAT_SELF_SIGNED;
+ static const std::string JSON_PROOF_OF_PRIVATE_KEY;
+};
+
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDNCERT_CHALLENGE_PRIVATE_KEY_HPP