blob: 4d82f065104c5f447a23211a0ce6f103c68d8507 [file] [log] [blame]
Jeff Thompson25b4e612013-10-10 16:03:24 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
Jeff Thompson47c93cf2013-08-09 00:38:48 -07002/**
Jeff Thompson7687dc02013-09-13 11:54:07 -07003 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
Jeff Thompson47c93cf2013-08-09 00:38:48 -07005 * See COPYING for copyright and distribution information.
6 */
7
Jeff Thompson7a67cb62013-08-26 11:43:18 -07008#include "../c/util/crypto.h"
9#include "../c/encoding/binary-xml-data.h"
10#include "../encoding/binary-xml-encoder.hpp"
Jeff Thompson25b4e612013-10-10 16:03:24 -070011#include <ndn-cpp/sha256-with-rsa-signature.hpp>
Jeff Thompson9296f0c2013-09-23 18:10:27 -070012#include "../util/logging.hpp"
Jeff Thompson25b4e612013-10-10 16:03:24 -070013#include <ndn-cpp/security/security-exception.hpp>
14#include <ndn-cpp/security/policy/policy-manager.hpp>
Jeff Thompsonf309aa62013-10-31 17:03:54 -070015#include "policy/validation-request.hpp"
Jeff Thompson25b4e612013-10-10 16:03:24 -070016#include <ndn-cpp/security/key-chain.hpp>
Jeff Thompson47c93cf2013-08-09 00:38:48 -070017
18using namespace std;
Jeff Thompsond4144fe2013-09-18 15:59:57 -070019using namespace ndn::ptr_lib;
Jeff Thompson2381da82013-11-06 14:34:09 -080020using namespace ndn::func_lib;
Jeff Thompson9bdeb6d2013-11-06 14:30:07 -080021#if NDN_CPP_HAVE_STD_FUNCTION
Jeff Thompson09324ed2013-11-06 14:40:35 -080022// In the std library, the placeholders are in a different namespace than boost.
23using namespace ndn::func_lib::placeholders;
Jeff Thompson9bdeb6d2013-11-06 14:30:07 -080024#endif
Jeff Thompson47c93cf2013-08-09 00:38:48 -070025
26namespace ndn {
27
Jeff Thompson15966392013-12-04 17:37:17 -080028/**
29 * Verify the signature on the data packet using the given public key. If there is no data.getDefaultWireEncoding(),
30 * this calls data.wireEncode() to set it.
31 * @param data The data packet with the signed portion and the signature to verify. The data packet must have a
32 * Sha256WithRsaSignature.
33 * @param publicKey The public key used to verify the signature.
34 * @return true if the signature verifies, false if not.
35 * @throw SecurityException if data does not have a Sha256WithRsaSignature.
36 */
37static bool
38verifySha256WithRsaSignature(const Data& data, const PublicKey& publicKey)
39{
40 const Sha256WithRsaSignature *signature = dynamic_cast<const Sha256WithRsaSignature*>(data.getSignature());
41 if (!signature)
42 throw SecurityException("signature is not Sha256WithRsaSignature.");
43
44 // Set the data packet's default wire encoding if it is not already there.
45 if (signature->getDigestAlgorithm().size() != 0)
46 // TODO: Allow a non-default digest algorithm.
47 throw UnrecognizedDigestAlgorithmException("Cannot verify a data packet with a non-default digest algorithm.");
48 if (!data.getDefaultWireEncoding())
49 data.wireEncode();
50
51 // Set signedPortionDigest to the digest of the signed portion of the wire encoding.
52 uint8_t signedPortionDigest[SHA256_DIGEST_LENGTH];
53 ndn_digestSha256(data.getDefaultWireEncoding().signedBuf(), data.getDefaultWireEncoding().signedSize(), signedPortionDigest);
54
55 // Verify the signedPortionDigest.
56 // Use a temporary pointer since d2i updates it.
57 const uint8_t *derPointer = publicKey.getKeyDer().buf();
58 RSA *rsaPublicKey = d2i_RSA_PUBKEY(NULL, &derPointer, publicKey.getKeyDer().size());
59 if (!rsaPublicKey)
60 throw UnrecognizedKeyFormatException("Error decoding public key in d2i_RSAPublicKey");
61 int success = RSA_verify
62 (NID_sha256, signedPortionDigest, sizeof(signedPortionDigest), (uint8_t *)signature->getSignature().buf(),
63 signature->getSignature().size(), rsaPublicKey);
64 // Free the public key before checking for success.
65 RSA_free(rsaPublicKey);
66
67 // RSA_verify returns 1 for a valid signature.
68 return (success == 1);
69}
70
Jeff Thompson29ce3102013-09-27 11:47:48 -070071KeyChain::KeyChain(const shared_ptr<IdentityManager>& identityManager, const shared_ptr<PolicyManager>& policyManager)
72: identityManager_(identityManager), policyManager_(policyManager), face_(0), maxSteps_(100)
Jeff Thompson9296f0c2013-09-23 18:10:27 -070073{
74}
75
Jeff Thompson2ce8f492013-09-17 18:01:25 -070076void
Jeff Thompson29ce3102013-09-27 11:47:48 -070077KeyChain::sign(Data& data, const Name& certificateName, WireFormat& wireFormat)
Jeff Thompson2ce8f492013-09-17 18:01:25 -070078{
Jeff Thompson29ce3102013-09-27 11:47:48 -070079 identityManager_->signByCertificate(data, certificateName, wireFormat);
80}
81
Jeff Thompsonc01e1782013-10-21 14:08:42 -070082shared_ptr<Signature>
83KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
84{
85 return identityManager_->signByCertificate(buffer, bufferLength, certificateName);
86}
87
Jeff Thompson29ce3102013-09-27 11:47:48 -070088void
89KeyChain::signByIdentity(Data& data, const Name& identityName, WireFormat& wireFormat)
90{
91 Name signingCertificateName;
Jeff Thompson9296f0c2013-09-23 18:10:27 -070092
Jeff Thompson29ce3102013-09-27 11:47:48 -070093 if (identityName.getComponentCount() == 0) {
94 Name inferredIdentity = policyManager_->inferSigningIdentity(data.getName());
95 if (inferredIdentity.getComponentCount() == 0)
96 signingCertificateName = identityManager_->getDefaultCertificateName();
97 else
98 signingCertificateName = identityManager_->getDefaultCertificateNameForIdentity(inferredIdentity);
Jeff Thompson2ce8f492013-09-17 18:01:25 -070099 }
Jeff Thompson9296f0c2013-09-23 18:10:27 -0700100 else
Jeff Thompson29ce3102013-09-27 11:47:48 -0700101 signingCertificateName = identityManager_->getDefaultCertificateNameForIdentity(identityName);
102
103 if (signingCertificateName.getComponentCount() == 0)
104 throw SecurityException("No qualified certificate name found!");
105
106 if (!policyManager_->checkSigningPolicy(data.getName(), signingCertificateName))
Jeff Thompson9296f0c2013-09-23 18:10:27 -0700107 throw SecurityException("Signing Cert name does not comply with signing policy");
Jeff Thompson29ce3102013-09-27 11:47:48 -0700108
Jeff Thompson56e62652013-10-31 16:13:25 -0700109 identityManager_->signByCertificate(data, signingCertificateName, wireFormat);
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700110}
111
Jeff Thompsone9ffe792013-10-22 10:58:48 -0700112shared_ptr<Signature>
113KeyChain::signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
114{
115 Name signingCertificateName = identityManager_->getDefaultCertificateNameForIdentity(identityName);
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700116
Jeff Thompsone9ffe792013-10-22 10:58:48 -0700117 if (signingCertificateName.size() == 0)
118 throw SecurityException("No qualified certificate name found!");
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700119
Jeff Thompsone9ffe792013-10-22 10:58:48 -0700120 return identityManager_->signByCertificate(buffer, bufferLength, signingCertificateName);
121}
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700122
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700123void
Jeff Thompson7c5d2312013-09-25 16:07:15 -0700124KeyChain::verifyData
125 (const shared_ptr<Data>& data, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed, int stepCount)
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700126{
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700127 _LOG_TRACE("Enter Verify");
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700128
Jeff Thompsonf309aa62013-10-31 17:03:54 -0700129 if (policyManager_->requireVerify(*data)) {
130 shared_ptr<ValidationRequest> nextStep = policyManager_->checkVerificationPolicy
131 (data, stepCount, onVerified, onVerifyFailed);
Jeff Thompsoncda349e2013-11-05 17:37:39 -0800132 if (nextStep)
133 face_->expressInterest
134 (*nextStep->interest_,
135 bind(&KeyChain::onCertificateData, this, _1, _2, nextStep),
136 bind(&KeyChain::onCertificateInterestTimeout, this, _1, nextStep->retry_, onVerifyFailed, data, nextStep));
Jeff Thompsonf309aa62013-10-31 17:03:54 -0700137 }
138 else if (policyManager_->skipVerifyAndTrust(*data))
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700139 onVerified(data);
140 else
Jeff Thompson29ce3102013-09-27 11:47:48 -0700141 onVerifyFailed(data);
Jeff Thompson1e90d8c2013-08-12 16:09:25 -0700142}
143
Jeff Thompsoncda349e2013-11-05 17:37:39 -0800144void
145KeyChain::onCertificateData(const shared_ptr<const Interest> &interest, const shared_ptr<Data> &data, shared_ptr<ValidationRequest> nextStep)
146{
147 // Try to verify the certificate (data) according to the parameters in nextStep.
148 verifyData(data, nextStep->onVerified_, nextStep->onVerifyFailed_, nextStep->stepCount_);
149}
150
151void
152KeyChain::onCertificateInterestTimeout
153 (const shared_ptr<const Interest> &interest, int retry, const OnVerifyFailed& onVerifyFailed, const shared_ptr<Data> &data,
154 shared_ptr<ValidationRequest> nextStep)
155{
156 if (retry > 0)
157 // Issue the same expressInterest as in verifyData except decrement retry.
158 face_->expressInterest
159 (*interest,
160 bind(&KeyChain::onCertificateData, this, _1, _2, nextStep),
161 bind(&KeyChain::onCertificateInterestTimeout, this, _1, retry - 1, onVerifyFailed, data, nextStep));
162 else
163 onVerifyFailed(data);
164}
165
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700166}