security: CryptoPP functions are used directly to encode/decode DER/BER
This change eliminates the need for custom der decoder/encoder.
Change-Id: I5be2e55cec2b63157927a4ad87fffe8e8651ed3c
diff --git a/src/security/certificate/public-key.cpp b/src/security/certificate/public-key.cpp
index fc41a94..131e3c1 100644
--- a/src/security/certificate/public-key.cpp
+++ b/src/security/certificate/public-key.cpp
@@ -8,6 +8,8 @@
#include <ndn-cpp/common.hpp>
+#include "public-key.hpp"
+
#if NDN_CPP_USE_SYSTEM_BOOST
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/array.hpp>
@@ -18,49 +20,109 @@
#include <ndnboost/iostreams/device/array.hpp>
#endif
-#include <ndn-cpp/security/security-exception.hpp>
-#include "../../c/util/crypto.h"
-#include "../../encoding/der/der.hpp"
-#include <ndn-cpp/security/certificate/public-key.hpp>
+#include <cryptopp/rsa.h>
+#include <cryptopp/base64.h>
+#include <cryptopp/files.h>
using namespace std;
+using namespace CryptoPP;
namespace ndn {
-ptr_lib::shared_ptr<der::DerNode>
-PublicKey::toDer()
-{
- ndnboost::iostreams::stream<ndnboost::iostreams::array_source> is((const char*)keyDer_.buf (), keyDer_.size ());
+static OID RSA_OID("1.2.840.113549.1.1.1");
- return der::DerNode::parse(reinterpret_cast<der::InputIterator&> (is));
+PublicKey::PublicKey()
+{
}
-static int RSA_OID[] = { 1, 2, 840, 113549, 1, 1, 1 };
-
-ptr_lib::shared_ptr<PublicKey>
-PublicKey::fromDer(const Blob& keyDer)
+/**
+ * Create a new PublicKey with the given values.
+ * @param algorithm The algorithm of the public key.
+ * @param keyDer The blob of the PublicKeyInfo in terms of DER.
+ */
+PublicKey::PublicKey(const uint8_t *keyDerBuf, size_t keyDerSize)
{
- // Use a temporary pointer since d2i updates it.
- const uint8_t *derPointer = keyDer.buf();
- RSA *publicKey = d2i_RSA_PUBKEY(NULL, &derPointer, keyDer.size());
- if (!publicKey)
- throw UnrecognizedKeyFormatException("Error decoding public key DER");
- RSA_free(publicKey);
-
- return ptr_lib::shared_ptr<PublicKey>(new PublicKey(OID(vector<int>(RSA_OID, RSA_OID + sizeof(RSA_OID))), keyDer));
+ StringSource src(keyDerBuf, keyDerSize, true);
+ decode(src);
}
-Blob
-PublicKey::getDigest(DigestAlgorithm digestAlgorithm) const
+void
+PublicKey::encode(CryptoPP::BufferedTransformation &out) const
{
- if (digestAlgorithm == DIGEST_ALGORITHM_SHA256) {
- uint8_t digest[SHA256_DIGEST_LENGTH];
- ndn_digestSha256(keyDer_.buf(), keyDer_.size(), digest);
-
- return Blob(digest, sizeof(digest));
+ // SubjectPublicKeyInfo ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier
+ // keybits BIT STRING }
+
+ out.Put(key_.buf(), key_.size());
+}
+
+void
+PublicKey::decode(CryptoPP::BufferedTransformation &in)
+{
+ // SubjectPublicKeyInfo ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier
+ // keybits BIT STRING }
+
+ try {
+ std::string out;
+ StringSink sink(out);
+
+ ////////////////////////
+ // part 1: copy as is //
+ ////////////////////////
+ BERSequenceDecoder decoder(in);
+ {
+ assert (decoder.IsDefiniteLength());
+
+ DERSequenceEncoder encoder(sink);
+ decoder.TransferTo(encoder, decoder.RemainingLength());
+ encoder.MessageEnd();
+ }
+ decoder.MessageEnd();
+
+ ////////////////////////
+ // part 2: check if the key is RSA (since it is the only supported for now)
+ ////////////////////////
+ StringSource checkedSource(out, true);
+ BERSequenceDecoder subjectPublicKeyInfo(checkedSource);
+ {
+ BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
+ {
+ OID algorithm;
+ algorithm.decode(algorithmInfo);
+
+ if (algorithm != RSA_OID)
+ throw Error("Only RSA public keys are supported for now (" + algorithm.toString() + " requested");
+ }
+ }
+
+ key_.assign(out.begin(), out.end());
}
- else
- throw UnrecognizedDigestAlgorithmException("Wrong format!");
+ catch (CryptoPP::BERDecodeErr &err) {
+ throw Error("PublicKey decoding error");
+ }
+}
+
+// Blob
+// PublicKey::getDigest(DigestAlgorithm digestAlgorithm) const
+// {
+// if (digestAlgorithm == DIGEST_ALGORITHM_SHA256) {
+// uint8_t digest[SHA256_DIGEST_LENGTH];
+// ndn_digestSha256(keyDer_.buf(), keyDer_.size(), digest);
+
+// return Blob(digest, sizeof(digest));
+// }
+// else
+// throw UnrecognizedDigestAlgorithmException("Wrong format!");
+// }
+
+std::ostream &
+operator <<(std::ostream &os, const PublicKey &key)
+{
+ CryptoPP::StringSource(key.get().buf(), key.get().size(), true,
+ new CryptoPP::Base64Encoder(new CryptoPP::FileSink(os), true, 64));
+
+ return os;
}
}