This repository has been archived by the owner on Mar 19, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
/
ccnx-verifier.cpp
169 lines (147 loc) · 5.23 KB
/
ccnx-verifier.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2013 University of California, Los Angeles
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program 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 a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
* Alexander Afanasyev <alexander.afanasyev@ucla.edu>
*/
#include "ccnx-verifier.h"
#include "ccnx-wrapper.h"
INIT_LOGGER ("Ccnx.Verifier");
namespace Ccnx {
static const size_t ROOT_KEY_DIGEST_LEN = 32; // SHA-256
static const unsigned char ROOT_KEY_DIGEST[ROOT_KEY_DIGEST_LEN] = {0xa7, 0xd9, 0x8b, 0x81, 0xde, 0x13, 0xfc,
0x56, 0xc5, 0xa6, 0x92, 0xb4, 0x44, 0x93, 0x6e, 0x56, 0x70, 0x9d, 0x52, 0x6f, 0x70,
0xed, 0x39, 0xef, 0xb5, 0xe2, 0x3, 0x29, 0xa5, 0x53, 0x3e, 0x68};
Verifier::Verifier(CcnxWrapper *ccnx)
: m_ccnx(ccnx)
, m_rootKeyDigest(ROOT_KEY_DIGEST, ROOT_KEY_DIGEST_LEN)
{
}
Verifier::~Verifier()
{
}
bool
Verifier::verify(const PcoPtr &pco, double maxWait)
{
_LOG_TRACE("Verifying content [" << pco->name() << "]");
HashPtr publisherPublicKeyDigest = pco->publisherPublicKeyDigest();
{
UniqueRecLock lock(m_cacheLock);
CertCache::iterator it = m_certCache.find(*publisherPublicKeyDigest);
if (it != m_certCache.end())
{
CertPtr cert = it->second;
if (cert->validity() == Cert::WITHIN_VALID_TIME_SPAN)
{
pco->verifySignature(cert);
return pco->verified();
}
else
{
// delete the invalid cert cache
m_certCache.erase(it);
}
}
}
// keyName is the name specified in key locator, i.e. without version and segment
Name keyName = pco->keyName();
int keyNameSize = keyName.size();
if (keyNameSize < 2)
{
_LOG_ERROR("Key name is empty or has too few components.");
return false;
}
// for keys, we have to make sure key name is strictly prefix of the content name
if (pco->type() == ParsedContentObject::KEY)
{
Name contentName = pco->name();
// when checking for prefix, do not include the hash in the key name (which is the last component)
Name keyNamePrefix = keyName.getPartialName(0, keyNameSize - 1);
if (keyNamePrefix.size() >= contentName.size() || contentName.getPartialName(0, keyNamePrefix.size()) != keyNamePrefix)
{
_LOG_ERROR("Key name prefix [" << keyNamePrefix << "] is not the prefix of content name [" << contentName << "]");
return false;
}
}
else
{
// for now, user can assign any data using his key
}
Name metaName = keyName.getPartialName(0, keyNameSize - 1) + Name("/info") + keyName.getPartialName(keyNameSize - 1);
Selectors selectors;
selectors.childSelector(Selectors::RIGHT)
.interestLifetime(maxWait);
PcoPtr keyObject = m_ccnx->get(keyName, selectors, maxWait);
PcoPtr metaObject = m_ccnx->get(metaName, selectors, maxWait);
if (!keyObject || !metaObject )
{
_LOG_ERROR("can not fetch key or meta");
return false;
}
HashPtr publisherKeyHashInKeyObject = keyObject->publisherPublicKeyDigest();
HashPtr publisherKeyHashInMetaObject = metaObject->publisherPublicKeyDigest();
// make sure key and meta are signed using the same key
if (publisherKeyHashInKeyObject->IsZero() || ! (*publisherKeyHashInKeyObject == *publisherKeyHashInMetaObject))
{
_LOG_ERROR("Key and Meta not signed by the same publisher");
return false;
}
CertPtr cert = boost::make_shared<Cert>(keyObject, metaObject);
if (cert->validity() != Cert::WITHIN_VALID_TIME_SPAN)
{
_LOG_ERROR("Certificate is not valid, validity status is : " << cert->validity());
return false;
}
// check pco is actually signed by this key (i.e. we don't trust the publisherPublicKeyDigest given by ccnx c lib)
if (! (*pco->publisherPublicKeyDigest() == cert->keyDigest()))
{
_LOG_ERROR("key digest does not match the publisher public key digest of the content object");
return false;
}
// now we only need to make sure the key is trustworthy
if (cert->keyDigest() == m_rootKeyDigest)
{
// the key is the root key
// do nothing now
}
else
{
// can not verify key or can not verify meta
if (!verify(keyObject, maxWait) || !verify(metaObject, maxWait))
{
_LOG_ERROR("Can not verify key or meta");
return false;
}
}
// ok, keyObject verified, because metaObject is signed by the same parent key and integrity checked
// so metaObject is also verified
{
UniqueRecLock lock(m_cacheLock);
m_certCache.insert(std::make_pair(cert->keyDigest(), cert));
}
pco->verifySignature(cert);
if (pco->verified())
{
_LOG_TRACE("[" << pco->name() << "] VERIFIED.");
}
else
{
_LOG_ERROR("[" << pco->name() << "] CANNOT BE VERIFIED.");
}
return pco->verified();
}
} // Ccnx