blob: 2a8cd29f333c791b31d1427ef20b7c6cca0999ec [file] [log] [blame]
Alexander Afanasyev574aa862017-01-10 19:53:28 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento8aad3722017-09-16 20:57:28 -04002/*
Davide Pesavento35c63792022-01-17 02:06:03 -05003 * Copyright (c) 2013-2022 Regents of the University of California.
Alexander Afanasyev574aa862017-01-10 19:53:28 -08004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
Davide Pesavento7e780642018-11-24 15:51:34 -050022#include "ndn-cxx/security/verification-helpers.hpp"
Alexander Afanasyev574aa862017-01-10 19:53:28 -080023
Davide Pesavento7e780642018-11-24 15:51:34 -050024#include "ndn-cxx/data.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050025#include "ndn-cxx/encoding/buffer-stream.hpp"
Alexander Afanasyev09236c22020-06-03 13:42:38 -040026#include "ndn-cxx/interest.hpp"
27#include "ndn-cxx/security/certificate.hpp"
Junxiao Shi24c5a002018-12-12 04:47:15 +000028#include "ndn-cxx/security/impl/openssl.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050029#include "ndn-cxx/security/pib/key.hpp"
laqinfanbc997e52019-06-25 22:11:09 -050030#include "ndn-cxx/security/tpm/tpm.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050031#include "ndn-cxx/security/transform/bool-sink.hpp"
32#include "ndn-cxx/security/transform/buffer-source.hpp"
33#include "ndn-cxx/security/transform/digest-filter.hpp"
34#include "ndn-cxx/security/transform/public-key.hpp"
35#include "ndn-cxx/security/transform/stream-sink.hpp"
36#include "ndn-cxx/security/transform/verifier-filter.hpp"
Alexander Afanasyev574aa862017-01-10 19:53:28 -080037
38namespace ndn {
39namespace security {
40
laqinfanbc997e52019-06-25 22:11:09 -050041namespace {
42
Eric Newberryb74bbda2020-06-18 19:33:58 -070043class ParseResult
laqinfanbc997e52019-06-25 22:11:09 -050044{
Eric Newberryb74bbda2020-06-18 19:33:58 -070045public:
46 ParseResult() = default;
47
Davide Pesavento765abc92021-12-27 00:44:04 -050048 ParseResult(SignatureInfo info, InputBuffers bufs, span<const uint8_t> sig)
Justin Labryaef53b62021-03-10 06:07:27 +000049 : info(std::move(info))
50 , bufs(std::move(bufs))
Eric Newberryb74bbda2020-06-18 19:33:58 -070051 , sig(sig)
Eric Newberryb74bbda2020-06-18 19:33:58 -070052 {
53 }
54
55public:
Justin Labryaef53b62021-03-10 06:07:27 +000056 SignatureInfo info;
Eric Newberryb74bbda2020-06-18 19:33:58 -070057 InputBuffers bufs;
Davide Pesavento765abc92021-12-27 00:44:04 -050058 span<const uint8_t> sig;
laqinfanbc997e52019-06-25 22:11:09 -050059};
60
61} // namespace
62
Alexander Afanasyev574aa862017-01-10 19:53:28 -080063bool
Davide Pesavento35c63792022-01-17 02:06:03 -050064verifySignature(const InputBuffers& blobs, span<const uint8_t> sig, const transform::PublicKey& key)
Alexander Afanasyev574aa862017-01-10 19:53:28 -080065{
66 bool result = false;
67 try {
68 using namespace transform;
Davide Pesavento35c63792022-01-17 02:06:03 -050069 bufferSource(blobs) >> verifierFilter(DigestAlgorithm::SHA256, key, sig)
Eric Newberryb74bbda2020-06-18 19:33:58 -070070 >> boolSink(result);
Alexander Afanasyev574aa862017-01-10 19:53:28 -080071 }
72 catch (const transform::Error&) {
73 return false;
74 }
Eric Newberryb74bbda2020-06-18 19:33:58 -070075
Alexander Afanasyev574aa862017-01-10 19:53:28 -080076 return result;
77}
78
79bool
Davide Pesavento35c63792022-01-17 02:06:03 -050080verifySignature(const InputBuffers& blobs, span<const uint8_t> sig, span<const uint8_t> key)
Alexander Afanasyev574aa862017-01-10 19:53:28 -080081{
Davide Pesavento77d9e812019-06-03 22:05:54 -040082 transform::PublicKey pKey;
Alexander Afanasyev574aa862017-01-10 19:53:28 -080083 try {
Davide Pesavento35c63792022-01-17 02:06:03 -050084 pKey.loadPkcs8(key);
Alexander Afanasyev574aa862017-01-10 19:53:28 -080085 }
86 catch (const transform::Error&) {
87 return false;
88 }
89
Davide Pesavento35c63792022-01-17 02:06:03 -050090 return verifySignature(blobs, sig, pKey);
Eric Newberryb74bbda2020-06-18 19:33:58 -070091}
92
laqinfanbc997e52019-06-25 22:11:09 -050093static ParseResult
Alexander Afanasyev574aa862017-01-10 19:53:28 -080094parse(const Data& data)
95{
96 try {
Justin Labryaef53b62021-03-10 06:07:27 +000097 return ParseResult(data.getSignatureInfo(),
98 data.extractSignedRanges(),
Davide Pesavento765abc92021-12-27 00:44:04 -050099 {data.getSignatureValue().value(), data.getSignatureValue().value_size()});
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800100 }
101 catch (const tlv::Error&) {
laqinfanbc997e52019-06-25 22:11:09 -0500102 return ParseResult();
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800103 }
104}
105
laqinfanbc997e52019-06-25 22:11:09 -0500106static ParseResult
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800107parse(const Interest& interest)
108{
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800109 try {
Eric Newberryb74bbda2020-06-18 19:33:58 -0700110 interest.wireEncode();
111
112 if (interest.getSignatureInfo() && interest.getSignatureValue().isValid()) {
113 // Verify using v0.3 Signed Interest semantics
114 Block sigValue = interest.getSignatureValue();
Justin Labryaef53b62021-03-10 06:07:27 +0000115 return ParseResult(*interest.getSignatureInfo(),
116 interest.extractSignedRanges(),
Davide Pesavento765abc92021-12-27 00:44:04 -0500117 {sigValue.value(), sigValue.value_size()});
Eric Newberryb74bbda2020-06-18 19:33:58 -0700118 }
119 else {
120 // Verify using older Signed Interest semantics
121 const Name& interestName = interest.getName();
122 if (interestName.size() < signed_interest::MIN_SIZE) {
123 return ParseResult();
124 }
125
126 const Block& nameBlock = interestName.wireEncode();
Justin Labryaef53b62021-03-10 06:07:27 +0000127 SignatureInfo info(interestName[signed_interest::POS_SIG_INFO].blockFromValue());
Davide Pesavento809f7542021-03-24 18:53:05 -0400128 Block sigValue(interestName[signed_interest::POS_SIG_VALUE].blockFromValue());
Justin Labryaef53b62021-03-10 06:07:27 +0000129 return ParseResult(info,
130 {{nameBlock.value(),
Eric Newberryb74bbda2020-06-18 19:33:58 -0700131 nameBlock.value_size() - interestName[signed_interest::POS_SIG_VALUE].size()}},
Davide Pesavento765abc92021-12-27 00:44:04 -0500132 {sigValue.value(),
133 sigValue.value_size()});
Eric Newberryb74bbda2020-06-18 19:33:58 -0700134 }
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800135 }
136 catch (const tlv::Error&) {
laqinfanbc997e52019-06-25 22:11:09 -0500137 return ParseResult();
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800138 }
139}
140
141static bool
Davide Pesavento809f7542021-03-24 18:53:05 -0400142verifySignature(const ParseResult& params, const transform::PublicKey& key)
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800143{
Davide Pesavento35c63792022-01-17 02:06:03 -0500144 return !params.bufs.empty() && verifySignature(params.bufs, params.sig, key);
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800145}
146
147static bool
Davide Pesavento765abc92021-12-27 00:44:04 -0500148verifySignature(const ParseResult& params, span<const uint8_t> key)
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800149{
Davide Pesavento35c63792022-01-17 02:06:03 -0500150 return !params.bufs.empty() && verifySignature(params.bufs, params.sig, key);
laqinfanbc997e52019-06-25 22:11:09 -0500151}
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800152
laqinfanbc997e52019-06-25 22:11:09 -0500153static bool
Davide Pesavento809f7542021-03-24 18:53:05 -0400154verifySignature(const ParseResult& params, const tpm::Tpm& tpm, const Name& keyName,
155 DigestAlgorithm digestAlgorithm)
laqinfanbc997e52019-06-25 22:11:09 -0500156{
Davide Pesavento35c63792022-01-17 02:06:03 -0500157 return !params.bufs.empty() && bool(tpm.verify(params.bufs, params.sig, keyName, digestAlgorithm));
Davide Pesavento809f7542021-03-24 18:53:05 -0400158}
159
160static bool
161verifyDigest(const ParseResult& params, DigestAlgorithm algorithm)
162{
163 if (params.bufs.empty()) {
164 return false;
165 }
166
167 OBufferStream os;
168 try {
169 using namespace transform;
170 bufferSource(params.bufs) >> digestFilter(algorithm) >> streamSink(os);
171 }
172 catch (const transform::Error&) {
173 return false;
174 }
175 auto result = os.buf();
176
Davide Pesavento765abc92021-12-27 00:44:04 -0500177 if (result->size() != params.sig.size()) {
Davide Pesavento809f7542021-03-24 18:53:05 -0400178 return false;
179 }
180
181 // constant-time buffer comparison to mitigate timing attacks
Davide Pesavento765abc92021-12-27 00:44:04 -0500182 return CRYPTO_memcmp(result->data(), params.sig.data(), params.sig.size()) == 0;
Davide Pesavento809f7542021-03-24 18:53:05 -0400183}
184
185bool
Davide Pesavento35c63792022-01-17 02:06:03 -0500186verifySignature(const Data& data, span<const uint8_t> key)
Davide Pesavento809f7542021-03-24 18:53:05 -0400187{
Davide Pesavento35c63792022-01-17 02:06:03 -0500188 return verifySignature(parse(data), key);
Davide Pesavento809f7542021-03-24 18:53:05 -0400189}
190
191bool
Davide Pesavento35c63792022-01-17 02:06:03 -0500192verifySignature(const Interest& interest, span<const uint8_t> key)
Davide Pesavento809f7542021-03-24 18:53:05 -0400193{
Davide Pesavento35c63792022-01-17 02:06:03 -0500194 return verifySignature(parse(interest), key);
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800195}
196
197bool
Davide Pesavento77d9e812019-06-03 22:05:54 -0400198verifySignature(const Data& data, const transform::PublicKey& key)
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800199{
200 return verifySignature(parse(data), key);
201}
202
203bool
Davide Pesavento77d9e812019-06-03 22:05:54 -0400204verifySignature(const Interest& interest, const transform::PublicKey& key)
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800205{
206 return verifySignature(parse(interest), key);
207}
208
209bool
210verifySignature(const Data& data, const pib::Key& key)
211{
Davide Pesavento765abc92021-12-27 00:44:04 -0500212 return verifySignature(parse(data), key.getPublicKey());
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800213}
214
215bool
216verifySignature(const Interest& interest, const pib::Key& key)
217{
Davide Pesavento765abc92021-12-27 00:44:04 -0500218 return verifySignature(parse(interest), key.getPublicKey());
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800219}
220
221bool
Davide Pesaventof2cae612021-03-24 18:47:05 -0400222verifySignature(const Data& data, const optional<Certificate>& cert)
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800223{
Justin Labryaef53b62021-03-10 06:07:27 +0000224 auto parsed = parse(data);
225 if (cert) {
Davide Pesavento35c63792022-01-17 02:06:03 -0500226 return verifySignature(parsed, {cert->getContent().value(), cert->getContent().value_size()});
Justin Labryaef53b62021-03-10 06:07:27 +0000227 }
Davide Pesavento809f7542021-03-24 18:53:05 -0400228 else if (parsed.info.getSignatureType() == tlv::SignatureTypeValue::DigestSha256) {
229 return verifyDigest(parsed, DigestAlgorithm::SHA256);
230 }
231 // Add any other self-verifying signatures here (if any)
Justin Labryaef53b62021-03-10 06:07:27 +0000232 else {
Davide Pesavento809f7542021-03-24 18:53:05 -0400233 return false;
Justin Labryaef53b62021-03-10 06:07:27 +0000234 }
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800235}
236
237bool
Davide Pesaventof2cae612021-03-24 18:47:05 -0400238verifySignature(const Interest& interest, const optional<Certificate>& cert)
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800239{
Justin Labryaef53b62021-03-10 06:07:27 +0000240 auto parsed = parse(interest);
241 if (cert) {
Davide Pesavento35c63792022-01-17 02:06:03 -0500242 return verifySignature(parsed, {cert->getContent().value(), cert->getContent().value_size()});
Justin Labryaef53b62021-03-10 06:07:27 +0000243 }
Davide Pesavento809f7542021-03-24 18:53:05 -0400244 else if (parsed.info.getSignatureType() == tlv::SignatureTypeValue::DigestSha256) {
245 return verifyDigest(parsed, DigestAlgorithm::SHA256);
246 }
247 // Add any other self-verifying signatures here (if any)
Justin Labryaef53b62021-03-10 06:07:27 +0000248 else {
Davide Pesavento809f7542021-03-24 18:53:05 -0400249 return false;
Justin Labryaef53b62021-03-10 06:07:27 +0000250 }
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800251}
252
laqinfanbc997e52019-06-25 22:11:09 -0500253bool
254verifySignature(const Data& data, const tpm::Tpm& tpm,
255 const Name& keyName, DigestAlgorithm digestAlgorithm)
256{
257 return verifySignature(parse(data), tpm, keyName, digestAlgorithm);
258}
259
260bool
261verifySignature(const Interest& interest, const tpm::Tpm& tpm,
262 const Name& keyName, DigestAlgorithm digestAlgorithm)
263{
264 return verifySignature(parse(interest), tpm, keyName, digestAlgorithm);
265}
266
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800267} // namespace security
268} // namespace ndn