blob: 07b8137edf6f2642b2708c76cac6bdf49a34dffa [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Jeff Thompsonc0573432013-09-19 17:41:36 -07002/**
Alexander Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * 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.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
22 * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
Jeff Thompsonc0573432013-09-19 17:41:36 -070023 */
24
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080025#include "public-key.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070026
27#include "../encoding/oid.hpp"
Yingdi Yue36322a2014-11-04 14:16:54 -080028#include "../util/crypto.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070029#include "cryptopp.hpp"
Jeff Thompsonc0573432013-09-19 17:41:36 -070030
Jeff Thompsonc0573432013-09-19 17:41:36 -070031namespace ndn {
32
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080033PublicKey::PublicKey()
Yingdi Yu2620b1c2014-06-12 15:32:57 -070034 : m_type(KEY_TYPE_NULL)
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080035{
Jeff Thompsonc0573432013-09-19 17:41:36 -070036}
Jeff Thompsonc0573432013-09-19 17:41:36 -070037
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070038PublicKey::PublicKey(const uint8_t* keyDerBuf, size_t keyDerSize)
Yingdi Yu2620b1c2014-06-12 15:32:57 -070039 : m_type(KEY_TYPE_NULL)
Jeff Thompsonc0573432013-09-19 17:41:36 -070040{
Yingdi Yu5ec0ee32014-06-24 16:26:09 -070041 CryptoPP::StringSource src(keyDerBuf, keyDerSize, true);
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080042 decode(src);
Jeff Thompsonc0573432013-09-19 17:41:36 -070043}
44
Yingdi Yue36322a2014-11-04 14:16:54 -080045const Block&
46PublicKey::computeDigest() const
47{
48 if (m_key.empty())
49 throw Error("Public key is empty");
50
51 if (m_digest.hasWire())
52 return m_digest;
53 else {
54 m_digest = Block(tlv::KeyDigest, crypto::sha256(m_key.buf(), m_key.size()));
55 m_digest.encode();
56 return m_digest;
57 }
58}
59
60
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080061void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070062PublicKey::encode(CryptoPP::BufferedTransformation& out) const
Jeff Thompsonc0573432013-09-19 17:41:36 -070063{
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080064 // SubjectPublicKeyInfo ::= SEQUENCE {
65 // algorithm AlgorithmIdentifier
66 // keybits BIT STRING }
67
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070068 out.Put(m_key.buf(), m_key.size());
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080069}
70
71void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070072PublicKey::decode(CryptoPP::BufferedTransformation& in)
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080073{
74 // SubjectPublicKeyInfo ::= SEQUENCE {
75 // algorithm AlgorithmIdentifier
76 // keybits BIT STRING }
77
Yingdi Yu5ec0ee32014-06-24 16:26:09 -070078 using namespace CryptoPP;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070079 try
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080080 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070081 std::string out;
82 StringSink sink(out);
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080083
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070084 ////////////////////////
85 // part 1: copy as is //
86 ////////////////////////
87 BERSequenceDecoder decoder(in);
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080088 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070089 assert(decoder.IsDefiniteLength());
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080090
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070091 DERSequenceEncoder encoder(sink);
92 decoder.TransferTo(encoder, decoder.RemainingLength());
93 encoder.MessageEnd();
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080094 }
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070095 decoder.MessageEnd();
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080096
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070097 ////////////////////////
98 // part 2: check if the key is RSA (since it is the only supported for now)
99 ////////////////////////
100 StringSource checkedSource(out, true);
101 BERSequenceDecoder subjectPublicKeyInfo(checkedSource);
102 {
103 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
104 {
105 OID algorithm;
106 algorithm.decode(algorithmInfo);
107
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700108 if (algorithm == oid::RSA)
Yingdi Yu2620b1c2014-06-12 15:32:57 -0700109 m_type = KEY_TYPE_RSA;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700110 else if (algorithm == oid::ECDSA)
Yingdi Yu2620b1c2014-06-12 15:32:57 -0700111 m_type = KEY_TYPE_ECDSA;
112 else
113 throw Error("Only RSA/ECDSA public keys are supported for now (" +
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700114 algorithm.toString() + " requested)");
115 }
116 }
117
118 m_key.assign(out.begin(), out.end());
119 }
120 catch (CryptoPP::BERDecodeErr& err)
121 {
Yingdi Yu2620b1c2014-06-12 15:32:57 -0700122 m_type = KEY_TYPE_NULL;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700123 throw Error("PublicKey decoding error");
124 }
Yingdi Yue36322a2014-11-04 14:16:54 -0800125
126 m_digest.reset();
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800127}
128
129// Blob
130// PublicKey::getDigest(DigestAlgorithm digestAlgorithm) const
131// {
132// if (digestAlgorithm == DIGEST_ALGORITHM_SHA256) {
133// uint8_t digest[SHA256_DIGEST_LENGTH];
134// ndn_digestSha256(keyDer_.buf(), keyDer_.size(), digest);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700135
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800136// return Blob(digest, sizeof(digest));
137// }
138// else
139// throw UnrecognizedDigestAlgorithmException("Wrong format!");
140// }
141
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700142std::ostream&
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700143operator<<(std::ostream& os, const PublicKey& key)
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800144{
145 CryptoPP::StringSource(key.get().buf(), key.get().size(), true,
146 new CryptoPP::Base64Encoder(new CryptoPP::FileSink(os), true, 64));
147
148 return os;
Jeff Thompsonc0573432013-09-19 17:41:36 -0700149}
150
Yingdi Yufc40d872014-02-18 12:56:04 -0800151} // namespace ndn