blob: d5a4b6bb78218ec23062276ae7919022f8fac9ee [file] [log] [blame]
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -07001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013 University of California, Los Angeles
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
19 * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
20 */
21
22#include "ccnx-verifier.h"
Zhenkai Zhu746d4442013-03-13 17:06:54 -070023#include "ccnx-wrapper.h"
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -070024
Zhenkai Zhu203dfd22013-03-13 21:35:48 -070025INIT_LOGGER ("Ccnx.Verifier");
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -070026namespace Ccnx {
27
28static const size_t ROOT_KEY_DIGEST_LEN = 32; // SHA-256
29static const unsigned char ROOT_KEY_DIGEST[ROOT_KEY_DIGEST_LEN] = {0xa7, 0xd9, 0x8b, 0x81, 0xde, 0x13, 0xfc,
300x56, 0xc5, 0xa6, 0x92, 0xb4, 0x44, 0x93, 0x6e, 0x56, 0x70, 0x9d, 0x52, 0x6f, 0x70,
310xed, 0x39, 0xef, 0xb5, 0xe2, 0x3, 0x29, 0xa5, 0x53, 0x3e, 0x68};
32
33Verifier::Verifier(CcnxWrapper *ccnx)
34 : m_ccnx(ccnx)
35 , m_rootKeyDigest(ROOT_KEY_DIGEST, ROOT_KEY_DIGEST_LEN)
36{
37}
38
39Verifier::~Verifier()
40{
41}
42
43bool
Zhenkai Zhud5d99be2013-03-13 19:15:56 -070044Verifier::verify(const PcoPtr &pco, double maxWait)
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -070045{
Zhenkai Zhu203dfd22013-03-13 21:35:48 -070046 _LOG_TRACE("Verifying content [" << pco->name() << "]");
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -070047 HashPtr publisherPublicKeyDigest = pco->publisherPublicKeyDigest();
Zhenkai Zhu746d4442013-03-13 17:06:54 -070048
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -070049 {
Zhenkai Zhu746d4442013-03-13 17:06:54 -070050 UniqueRecLock lock(m_cacheLock);
51 CertCache::iterator it = m_certCache.find(*publisherPublicKeyDigest);
52 if (it != m_certCache.end())
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -070053 {
Zhenkai Zhu746d4442013-03-13 17:06:54 -070054 CertPtr cert = it->second;
55 if (cert->validity() == Cert::WITHIN_VALID_TIME_SPAN)
56 {
Zhenkai Zhud5d99be2013-03-13 19:15:56 -070057 pco->verifySignature(cert);
58 return pco->verified();
Zhenkai Zhu746d4442013-03-13 17:06:54 -070059 }
60 else
61 {
62 // delete the invalid cert cache
63 m_certCache.erase(it);
64 }
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -070065 }
66 }
67
68 // keyName is the name specified in key locator, i.e. without version and segment
69 Name keyName = pco->keyName();
70 int keyNameSize = keyName.size();
71
Zhenkai Zhu203dfd22013-03-13 21:35:48 -070072 if (keyNameSize < 2)
Zhenkai Zhu9dd9adc2013-03-13 16:12:09 -070073 {
Zhenkai Zhu203dfd22013-03-13 21:35:48 -070074 _LOG_ERROR("Key name is empty or has too few components.");
Zhenkai Zhu9dd9adc2013-03-13 16:12:09 -070075 return false;
76 }
77
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -070078 // for keys, we have to make sure key name is strictly prefix of the content name
79 if (pco->type() == ParsedContentObject::KEY)
80 {
81 Name contentName = pco->name();
Zhenkai Zhu203dfd22013-03-13 21:35:48 -070082 // when checking for prefix, do not include the hash in the key name (which is the last component)
83 Name keyNamePrefix = keyName.getPartialName(0, keyNameSize - 1);
84 if (keyNamePrefix.size() >= contentName.size() || contentName.getPartialName(0, keyNamePrefix.size()) != keyNamePrefix)
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -070085 {
Zhenkai Zhu203dfd22013-03-13 21:35:48 -070086 _LOG_ERROR("Key name prefix [" << keyNamePrefix << "] is not the prefix of content name [" << contentName << "]");
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -070087 return false;
88 }
89 }
90 else
91 {
92 // for now, user can assign any data using his key
93 }
94
95 Name metaName = keyName.getPartialName(0, keyNameSize - 1) + Name("/info") + keyName.getPartialName(keyNameSize - 1);
96
97 Selectors selectors;
98
99 selectors.childSelector(Selectors::RIGHT)
Zhenkai Zhud5d99be2013-03-13 19:15:56 -0700100 .interestLifetime(maxWait);
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700101
Zhenkai Zhu203dfd22013-03-13 21:35:48 -0700102 PcoPtr keyObject = m_ccnx->get(keyName, selectors, maxWait);
103 PcoPtr metaObject = m_ccnx->get(metaName, selectors, maxWait);
Zhenkai Zhud5d99be2013-03-13 19:15:56 -0700104 if (!keyObject || !metaObject )
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700105 {
Zhenkai Zhu203dfd22013-03-13 21:35:48 -0700106 _LOG_ERROR("can not fetch key or meta");
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700107 return false;
108 }
109
110 HashPtr publisherKeyHashInKeyObject = keyObject->publisherPublicKeyDigest();
111 HashPtr publisherKeyHashInMetaObject = metaObject->publisherPublicKeyDigest();
112
113 // make sure key and meta are signed using the same key
114 if (publisherKeyHashInKeyObject->IsZero() || ! (*publisherKeyHashInKeyObject == *publisherKeyHashInMetaObject))
115 {
Zhenkai Zhu203dfd22013-03-13 21:35:48 -0700116 _LOG_ERROR("Key and Meta not signed by the same publisher");
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700117 return false;
118 }
119
Zhenkai Zhu9dd9adc2013-03-13 16:12:09 -0700120 CertPtr cert = boost::make_shared<Cert>(keyObject, metaObject);
121 if (cert->validity() != Cert::WITHIN_VALID_TIME_SPAN)
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700122 {
Zhenkai Zhu203dfd22013-03-13 21:35:48 -0700123 _LOG_ERROR("Certificate is not valid, validity status is : " << cert->validity());
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700124 return false;
125 }
126
Zhenkai Zhud5d99be2013-03-13 19:15:56 -0700127 // check pco is actually signed by this key (i.e. we don't trust the publisherPublicKeyDigest given by ccnx c lib)
Zhenkai Zhu9dd9adc2013-03-13 16:12:09 -0700128 if (! (*pco->publisherPublicKeyDigest() == cert->keyDigest()))
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700129 {
Zhenkai Zhu203dfd22013-03-13 21:35:48 -0700130 _LOG_ERROR("key digest does not match the publisher public key digest of the content object");
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700131 return false;
132 }
133
Zhenkai Zhu9dd9adc2013-03-13 16:12:09 -0700134 // now we only need to make sure the key is trustworthy
135 if (cert->keyDigest() == m_rootKeyDigest)
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700136 {
137 // the key is the root key
138 // do nothing now
139 }
140 else
141 {
Zhenkai Zhud5d99be2013-03-13 19:15:56 -0700142 // can not verify key or can not verify meta
143 if (!verify(keyObject, maxWait) || !verify(metaObject, maxWait))
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700144 {
Zhenkai Zhu203dfd22013-03-13 21:35:48 -0700145 _LOG_ERROR("Can not verify key or meta");
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700146 return false;
147 }
148 }
149
150 // ok, keyObject verified, because metaObject is signed by the same parent key and integrity checked
151 // so metaObject is also verified
Zhenkai Zhu746d4442013-03-13 17:06:54 -0700152 {
153 UniqueRecLock lock(m_cacheLock);
154 m_certCache.insert(std::make_pair(cert->keyDigest(), cert));
155 }
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700156
Zhenkai Zhud5d99be2013-03-13 19:15:56 -0700157 pco->verifySignature(cert);
Zhenkai Zhu203dfd22013-03-13 21:35:48 -0700158 if (pco->verified())
159 {
160 _LOG_TRACE("[" << pco->name() << "] VERIFIED.");
161 }
162 else
163 {
164 _LOG_ERROR("[" << pco->name() << "] CANNOT BE VERIFIED.");
165 }
Zhenkai Zhud5d99be2013-03-13 19:15:56 -0700166 return pco->verified();
Zhenkai Zhudd1f14d2013-03-13 12:04:28 -0700167}
168
169} // Ccnx