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/certificate-extension.cpp b/src/security/certificate/certificate-extension.cpp
index d9297a9..51c29ed 100644
--- a/src/security/certificate/certificate-extension.cpp
+++ b/src/security/certificate/certificate-extension.cpp
@@ -6,42 +6,51 @@
* See COPYING for copyright and distribution information.
*/
-#include "../../encoding/der/der.hpp"
-#include "../../util/blob-stream.hpp"
#include <ndn-cpp/security/certificate/certificate-extension.hpp>
+#include <cryptopp/asn.h>
using namespace std;
+using namespace CryptoPP;
namespace ndn {
-ptr_lib::shared_ptr<der::DerNode>
-CertificateExtension::toDer() const
+void
+CertificateExtension::encode(CryptoPP::BufferedTransformation &out) const
{
- ptr_lib::shared_ptr<der::DerSequence> root(new der::DerSequence);
-
- ptr_lib::shared_ptr<der::DerOid> extensionId(new der::DerOid(extensionId_));
- ptr_lib::shared_ptr<der::DerBool> isCritical(new der::DerBool(isCritical_));
- ptr_lib::shared_ptr<der::DerOctetString> extensionValue(new der::DerOctetString(*extensionValue_));
+ // Extension ::= SEQUENCE {
+ // extnID OBJECT IDENTIFIER,
+ // critical BOOLEAN DEFAULT FALSE,
+ // extnValue OCTET STRING }
- root->addChild(extensionId);
- root->addChild(isCritical);
- root->addChild(extensionValue);
-
- root->getSize();
-
- return root;
+ DERSequenceEncoder extension(out);
+ {
+ extensionId_.encode(extension);
+ DEREncodeUnsigned(extension, isCritical_, BOOLEAN);
+ DEREncodeOctetString(extension, extensionValue_.buf(), extensionValue_.size());
+ }
+ extension.MessageEnd();
}
-Blob
-CertificateExtension::toDerBlob() const
+void
+CertificateExtension::decode(CryptoPP::BufferedTransformation &in)
{
- blob_stream blobStream;
- der::OutputIterator& start = reinterpret_cast<der::OutputIterator&>(blobStream);
+ // Extension ::= SEQUENCE {
+ // extnID OBJECT IDENTIFIER,
+ // critical BOOLEAN DEFAULT FALSE,
+ // extnValue OCTET STRING }
- toDer()->encode(start);
+ BERSequenceDecoder extension(in);
+ {
+ extensionId_.decode(extension);
+ BERDecodeUnsigned(extension, isCritical_, BOOLEAN);
- return blobStream.buf();
+ // the extra copy operation can be optimized, but not trivial,
+ // since the length is not known in advance
+ SecByteBlock tmpBlock;
+ BERDecodeOctetString(extension, tmpBlock);
+ extensionValue_.assign(tmpBlock.begin(), tmpBlock.end());
+ }
+ extension.MessageEnd();
}
-
-
+
}
diff --git a/src/security/certificate/certificate-subject-description.cpp b/src/security/certificate/certificate-subject-description.cpp
index 3571f7f..472b30e 100644
--- a/src/security/certificate/certificate-subject-description.cpp
+++ b/src/security/certificate/certificate-subject-description.cpp
@@ -6,25 +6,58 @@
* See COPYING for copyright and distribution information.
*/
-#include "../../encoding/der/der.hpp"
#include <ndn-cpp/security/certificate/certificate-subject-description.hpp>
+#include <cryptopp/asn.h>
using namespace std;
+using namespace CryptoPP;
namespace ndn {
-ptr_lib::shared_ptr<der::DerNode>
-CertificateSubjectDescription::toDer() const
+void
+CertificateSubjectDescription::encode(CryptoPP::BufferedTransformation &out) const
{
- ptr_lib::shared_ptr<der::DerSequence> root(new der::DerSequence());
+ // RelativeDistinguishedName ::=
+ // SET OF AttributeTypeAndValue
+ //
+ // AttributeTypeAndValue ::= SEQUENCE {
+ // type AttributeType,
+ // value AttributeValue }
+ //
+ // AttributeType ::= OBJECT IDENTIFIER
+ //
+ // AttributeValue ::= ANY DEFINED BY AttributeType
+ DERSequenceEncoder attributeTypeAndValue(out);
+ {
+ oid_.encode(attributeTypeAndValue);
+ DEREncodeTextString(attributeTypeAndValue, value_, PRINTABLE_STRING);
+ }
+ attributeTypeAndValue.MessageEnd();
+}
- ptr_lib::shared_ptr<der::DerOid> oid(new der::DerOid(oid_));
- ptr_lib::shared_ptr<der::DerPrintableString> value(new der::DerPrintableString(value_));
+void
+CertificateSubjectDescription::decode(CryptoPP::BufferedTransformation &in)
+{
+ // RelativeDistinguishedName ::=
+ // SET OF AttributeTypeAndValue
+ //
+ // AttributeTypeAndValue ::= SEQUENCE {
+ // type AttributeType,
+ // value AttributeValue }
+ //
+ // AttributeType ::= OBJECT IDENTIFIER
+ //
+ // AttributeValue ::= ANY DEFINED BY AttributeType
- root->addChild(oid);
- root->addChild(value);
+ BERSequenceDecoder attributeTypeAndValue(in);
+ {
+ oid_.decode(attributeTypeAndValue);
- return root;
+ /// @todo May be add more intelligent processing, since the following
+ /// may fail if somebody encoded attribute that uses non PRINTABLE_STRING as value
+ BERDecodeTextString(attributeTypeAndValue, value_, PRINTABLE_STRING);
+ }
+ attributeTypeAndValue.MessageEnd();
}
}
diff --git a/src/security/certificate/certificate.cpp b/src/security/certificate/certificate.cpp
index 3275ac5..da88444 100644
--- a/src/security/certificate/certificate.cpp
+++ b/src/security/certificate/certificate.cpp
@@ -8,7 +8,7 @@
#include <ndn-cpp/common.hpp>
-#include <float.h>
+#include "certificate.hpp"
#if NDN_CPP_USE_SYSTEM_BOOST
#include <boost/iostreams/stream.hpp>
@@ -20,14 +20,16 @@
#include <ndnboost/iostreams/device/array.hpp>
#endif
-#include <ndn-cpp/sha256-with-rsa-signature.hpp>
-#include "../../encoding/der/der.hpp"
-#include "../../encoding/der/visitor/certificate-data-visitor.hpp"
-#include "../../encoding/der/visitor/print-visitor.hpp"
#include "../../util/logging.hpp"
-#include "../../util/blob-stream.hpp"
-#include "../../c/util/time.h"
-#include <ndn-cpp/security/certificate/certificate.hpp>
+// #include "../../util/blob-stream.hpp"
+// #include <ndn-cpp/security/certificate/certificate.hpp>
+#include "../../util/time.hpp"
+
+#include <cryptopp/asn.h>
+#include <cryptopp/base64.h>
+#include <cryptopp/files.h>
+
+#include "../../encoding/cryptopp/asn_ext.hpp"
INIT_LOGGER("ndn.security.Certificate");
@@ -36,8 +38,8 @@
namespace ndn {
Certificate::Certificate()
- : notBefore_(DBL_MAX)
- , notAfter_(-DBL_MAX)
+ : notBefore_(std::numeric_limits<MillisecondsSince1970>::max())
+ , notAfter_(std::numeric_limits<MillisecondsSince1970>::min())
{}
Certificate::Certificate(const Data& data)
@@ -77,80 +79,202 @@
void
Certificate::encode()
{
- ptr_lib::shared_ptr<der::DerSequence> root(new der::DerSequence());
+ // Name
+ // <key_name>/ID-CERT/<id#>
+ // Content
+ // DER encoded idCert:
+ //
+ // idCert ::= SEQUENCE {
+ // validity Validity,
+ // subject Name,
+ // subjectPubKeyInfo SubjectPublicKeyInfo,
+ // extension Extensions OPTIONAL }
+ //
+ // Validity ::= SEQUENCE {
+ // notBefore Time,
+ // notAfter Time }
+ //
+ // Name ::= CHOICE {
+ // RDNSequence }
+ //
+ // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ //
+ // RelativeDistinguishedName ::=
+ // SET OF AttributeTypeAndValue
+ //
+ // SubjectPublicKeyInfo ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier
+ // keybits BIT STRING }
+ //
+ // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ //
+ // (see http://www.ietf.org/rfc/rfc3280.txt for more detail)
+ //
+ // KeyLocator
+ // issuer’s certificate name
+ // Signature
+
+ using namespace CryptoPP;
+
+ OBufferStream os;
+ CryptoPP::FileSink sink(os);
- ptr_lib::shared_ptr<der::DerSequence> validity(new der::DerSequence());
- ptr_lib::shared_ptr<der::DerGtime> notBefore(new der::DerGtime(notBefore_));
- ptr_lib::shared_ptr<der::DerGtime> notAfter(new der::DerGtime(notAfter_));
- validity->addChild(notBefore);
- validity->addChild(notAfter);
- root->addChild(validity);
-
- ptr_lib::shared_ptr<der::DerSequence> subjectList(new der::DerSequence());
- SubjectDescriptionList::iterator it = subjectDescriptionList_.begin();
- for(; it != subjectDescriptionList_.end(); it++)
+ // idCert ::= SEQUENCE {
+ // validity Validity,
+ // subject Name,
+ // subjectPubKeyInfo SubjectPublicKeyInfo,
+ // extension Extensions OPTIONAL }
+ DERSequenceEncoder idCert(sink);
+ {
+ // Validity ::= SEQUENCE {
+ // notBefore Time,
+ // notAfter Time }
+ DERSequenceEncoder validity(idCert);
{
- ptr_lib::shared_ptr<der::DerNode> child = it->toDer();
- subjectList->addChild(child);
+ DEREncodeGeneralTime(validity, notBefore_);
+ DEREncodeGeneralTime(validity, notAfter_);
}
- root->addChild(subjectList);
+ validity.MessageEnd();
- root->addChild(key_.toDer());
-
- if(!extensionList_.empty())
+ // Name ::= CHOICE {
+ // RDNSequence }
+ //
+ // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ DERSequenceEncoder name(idCert);
{
- ptr_lib::shared_ptr<der::DerSequence> extnList(new der::DerSequence());
- ExtensionList::iterator it = extensionList_.begin();
- for(; it != extensionList_.end(); it++)
- extnList->addChild(it->toDer());
- root->addChild(extnList);
+ for(SubjectDescriptionList::iterator it = subjectDescriptionList_.begin();
+ it != subjectDescriptionList_.end(); ++it)
+ {
+ it->encode(name);
+ }
}
+ name.MessageEnd();
+
+ // SubjectPublicKeyInfo
+ key_.encode(idCert);
- blob_stream blobStream;
- der::OutputIterator& start = reinterpret_cast<der::OutputIterator&>(blobStream);
+ // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ //
+ // Extension ::= SEQUENCE {
+ // extnID OBJECT IDENTIFIER,
+ // critical BOOLEAN DEFAULT FALSE,
+ // extnValue OCTET STRING }
+ if(!extensionList_.empty())
+ {
+ DERSequenceEncoder extensions(idCert);
+ {
+
+ for(ExtensionList::iterator it = extensionList_.begin();
+ it != extensionList_.end(); ++it)
+ {
+ it->encode(extensions);
+ }
+ }
+ extensions.MessageEnd();
+ }
+ }
- root->encode(start);
+ idCert.MessageEnd();
- ptr_lib::shared_ptr<vector<uint8_t> > blob = blobStream.buf();
- setContent(blob);
- getMetaInfo().setType(ndn_ContentType_KEY);
+ setContent(os.buf());
+ setContentType(MetaInfo::TYPE_KEY);
}
void
Certificate::decode()
{
- Blob blob = getContent();
+ using namespace CryptoPP;
- ndnboost::iostreams::stream<ndnboost::iostreams::array_source> is((const char*)blob.buf(), blob.size());
+ OBufferStream os;
+ CryptoPP::StringSource source(getContent().value(), getContent().value_size(), true);
+
+ // idCert ::= SEQUENCE {
+ // validity Validity,
+ // subject Name,
+ // subjectPubKeyInfo SubjectPublicKeyInfo,
+ // extension Extensions OPTIONAL }
+ BERSequenceDecoder idCert(source);
+ {
+ // Validity ::= SEQUENCE {
+ // notBefore Time,
+ // notAfter Time }
+ BERSequenceDecoder validity(idCert);
+ {
+ BERDecodeTime(validity, notBefore_);
+ BERDecodeTime(validity, notAfter_);
+ }
+ validity.MessageEnd();
- ptr_lib::shared_ptr<der::DerNode> node = der::DerNode::parse(reinterpret_cast<der::InputIterator&>(is));
+ // Name ::= CHOICE {
+ // RDNSequence }
+ //
+ // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ subjectDescriptionList_.clear();
+ BERSequenceDecoder name(idCert);
+ {
+ while(!name.EndReached())
+ {
+ subjectDescriptionList_.push_back(CertificateSubjectDescription(name));
+ }
+ }
+ name.MessageEnd();
+
+ // SubjectPublicKeyInfo ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier
+ // keybits BIT STRING }
+ key_.decode(idCert);
- // der::PrintVisitor printVisitor;
- // node->accept(printVisitor, string(""));
+ // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ //
+ // Extension ::= SEQUENCE {
+ // extnID OBJECT IDENTIFIER,
+ // critical BOOLEAN DEFAULT FALSE,
+ // extnValue OCTET STRING }
+ extensionList_.clear();
+ if(!idCert.EndReached())
+ {
+ BERSequenceDecoder extensions(idCert);
+ {
+ while(!extensions.EndReached())
+ {
+ extensionList_.push_back(CertificateExtension(extensions));
+ }
+ }
+ extensions.MessageEnd();
+ }
+ }
- der::CertificateDataVisitor certDataVisitor;
- node->accept(certDataVisitor, this);
+ idCert.MessageEnd();
}
void
-Certificate::printCertificate()
+Certificate::printCertificate(std::ostream &os) const
{
- cout << "Validity:" << endl;
- cout << der::DerGtime::toIsoString(notBefore_) << endl;
- cout << der::DerGtime::toIsoString(notAfter_) << endl;
-
- cout << "Subject Info:" << endl;
- vector<CertificateSubjectDescription>::iterator it = subjectDescriptionList_.begin();
- for(; it < subjectDescriptionList_.end(); it++){
- cout << it->getOidString() << "\t" << it->getValue() << endl;
+ os << "Certificate name: " << endl;
+ os << " " << getName() << endl;
+ os << "Validity:" << endl;
+ {
+ os << " NotBefore: " << toIsoString(notBefore_) << endl;
+ os << " NotAfter: " << toIsoString(notAfter_) << endl;
}
- ndnboost::iostreams::stream<ndnboost::iostreams::array_source> is((const char*)key_.getKeyDer().buf(), key_.getKeyDer().size());
+ os << "Subject Description:" << endl;
+ for(SubjectDescriptionList::const_iterator it = subjectDescriptionList_.begin();
+ it != subjectDescriptionList_.end(); ++it)
+ {
+ os << " " << it->getOidString() << ": " << it->getValue() << endl;
+ }
- ptr_lib::shared_ptr<der::DerNode> keyRoot = der::DerNode::parse(reinterpret_cast<der::InputIterator&> (is));
+ os << "Public key bits: " << endl;
+ CryptoPP::Base64Encoder encoder(new CryptoPP::FileSink(os), true, 64);
+ key_.encode(encoder);
+
+ // ndnboost::iostreams::stream<ndnboost::iostreams::array_source> is((const char*)key_.getKeyDer().buf(), key_.getKeyDer().size());
- der::PrintVisitor printVisitor;
- keyRoot->accept(printVisitor, string(""));
+ // ptr_lib::shared_ptr<der::DerNode> keyRoot = der::DerNode::parse(reinterpret_cast<der::InputIterator&> (is));
+
+ // der::PrintVisitor printVisitor;
+ // keyRoot->accept(printVisitor, string(""));
}
}
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;
}
}