]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[sedhcpv6] spit xxx_asym.cc to xxx_rsa.{h,cc}
authorFrancis Dupont <fdupont@isc.org>
Sat, 6 Jun 2015 14:34:47 +0000 (16:34 +0200)
committerFrancis Dupont <fdupont@isc.org>
Sat, 6 Jun 2015 14:34:47 +0000 (16:34 +0200)
src/lib/cryptolink/Makefile.am
src/lib/cryptolink/botan_asym.cc
src/lib/cryptolink/botan_rsa.cc [new file with mode: 0644]
src/lib/cryptolink/botan_rsa.h [new file with mode: 0644]
src/lib/cryptolink/openssl_asym.cc
src/lib/cryptolink/openssl_rsa.cc [new file with mode: 0644]
src/lib/cryptolink/openssl_rsa.h [new file with mode: 0644]

index e7f69ab3feb3c803ae109534fcb44b2885f2432f..980c1157d76ff8f1c3d1d1b3003c7209770f05f6 100644 (file)
@@ -18,6 +18,7 @@ libkea_cryptolink_la_SOURCES += botan_common.h
 libkea_cryptolink_la_SOURCES += botan_hash.cc
 libkea_cryptolink_la_SOURCES += botan_hmac.cc
 libkea_cryptolink_la_SOURCES += botan_asym.cc
+libkea_cryptolink_la_SOURCES += botan_rsa.h botan_rsa.cc
 endif
 if HAVE_OPENSSL
 libkea_cryptolink_la_SOURCES += openssl_link.cc
@@ -25,6 +26,7 @@ libkea_cryptolink_la_SOURCES += openssl_common.h
 libkea_cryptolink_la_SOURCES += openssl_hash.cc
 libkea_cryptolink_la_SOURCES += openssl_hmac.cc
 libkea_cryptolink_la_SOURCES += openssl_asym.cc
+libkea_cryptolink_la_SOURCES += openssl_rsa.h openssl_rsa.cc
 endif
 
 libkea_cryptolink_la_LDFLAGS = ${CRYPTO_LDFLAGS}
index fd09f667fa5225a29a7a56dcc5b6230404001cbc..26cb75c5c87d6bfd96038faa731072f8aa3549db 100644 (file)
 #include <cryptolink.h>
 #include <cryptolink/crypto_asym.h>
 
-#include <boost/scoped_ptr.hpp>
-
 #include <botan/version.h>
 #include <botan/botan.h>
-#include <botan/hash.h>
-#include <botan/oids.h>
 #include <botan/pubkey.h>
 #include <botan/rsa.h>
 #include <botan/x509stor.h>
 
-#include <util/encode/base64.h>
 #include <hooks/hooks_manager.h>
 #include <hooks/callout_handle.h>
-#include <cryptolink/botan_common.h>
-
-#include <cstring>
-#include <fstream>
+#include <cryptolink/botan_rsa.h>
 
 namespace {
 
@@ -44,1182 +36,6 @@ int hook_point_validate_certificate =
 namespace isc {
 namespace cryptolink {
 
-/// @brief Botan implementation of asymmetrical cryptography (Asym).          
-// Each method is the counterpart of the Asym corresponding method.
-class RsaAsymImpl : public AsymImpl {
-public:
-    /// @brief Constructor from a key, asym and hash algorithm,
-    ///        key kind and key binary format
-    ///
-    /// See constructor of the @ref isc::cryptolink::Asym class for details.
-    ///
-    /// @param key            The key to sign/verify with
-    /// @param len            The length of the key
-    /// @param hash_algorithm The hash algorithm
-    /// @param key_kind       The key kind
-    /// @param key_format     The key binary format
-    RsaAsymImpl(const void* key, size_t key_len,
-                const HashAlgorithm hash_algorithm,
-                const AsymKeyKind key_kind,
-                const AsymFormat key_format) {
-        algo_ = RSA_;
-        hash_ = hash_algorithm;
-        kind_ = key_kind;
-        std::string hash = btn::getHashAlgorithmName(hash_);
-        if (hash.compare("Unknown") == 0) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown hash algorithm: " <<
-                      static_cast<int>(hash_));
-        }
-        std::string emsa = "EMSA3(" + hash + ")";
-        if (key_len == 0) {
-            isc_throw(BadKey, "Bad RSA " <<
-                      (kind_ != CERT ? "key" : "cert") <<
-                      " length: 0");
-        }
-
-        if ((kind_ == PRIVATE) && (key_format == BASIC)) {
-            // PKCS#1 Private Key
-            const Botan::byte* keyin =
-                reinterpret_cast<const Botan::byte*>(key);
-            const Botan::MemoryVector<Botan::byte> ber(keyin, key_len);
-            // rsaEncription OID and NULL parameters
-            const Botan::AlgorithmIdentifier alg_id =
-                Botan::AlgorithmIdentifier("1.2.840.113549.1.1.1",
-                    Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-            Botan::AutoSeeded_RNG rng;
-            try {
-                priv_.reset(new Botan::RSA_PrivateKey(alg_id, ber, rng));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "RSA_PrivateKey: " << exc.what());
-            }
-        } else if (kind_ == PRIVATE) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Private Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((kind_ == PUBLIC) && (key_format == BASIC)) {
-            // PKCS#1 Public Key
-            const Botan::byte* keyin =
-                reinterpret_cast<const Botan::byte*>(key);
-            const Botan::MemoryVector<Botan::byte> ber(keyin, key_len);
-            // rsaEncription OID and NULL parameters
-            const Botan::AlgorithmIdentifier alg_id =
-                Botan::AlgorithmIdentifier("1.2.840.113549.1.1.1",
-                    Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-            try {
-                pub_.reset(new Botan::RSA_PublicKey(alg_id, ber));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "RSA_PublicKey: " << exc.what());
-            }
-        } else if ((kind_ == PUBLIC) && (key_format == ASN1)) {
-            // SubjectPublicKeyInfo
-            const Botan::byte* keyin =
-                reinterpret_cast<const Botan::byte*>(key);
-            Botan::DataSource_Memory source(keyin, key_len);
-            Botan::Public_Key* key;
-            try {
-                key = Botan::X509::load_key(source);
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "X509::load_key: " << exc.what());
-            }
-            if (key->algo_name().compare("RSA") != 0) {
-                delete key;
-                isc_throw(BadKey, "not a RSA Public Key");
-            }
-            pub_.reset(dynamic_cast<Botan::RSA_PublicKey*>(key));
-            if (!pub_) {
-                delete key;
-                isc_throw(LibraryError, "dynamic_cast");
-            }
-        } else if ((kind_ == PUBLIC) && (key_format == DNS)) {
-            // RFC 3110 DNS wire format
-            // key_len == 0 was already checked
-            const uint8_t* p =
-                reinterpret_cast<const uint8_t*>(key);
-            size_t e_bytes = *p++;
-            --key_len;
-            if (e_bytes == 0) {
-                if (key_len < 2) {
-                    isc_throw(BadKey,
-                              "Bad RSA Public Key: short exponent length");
-                }
-                e_bytes = (*p++) << 8;
-                e_bytes += *p++;
-                key_len -= 2;
-            }
-            if (key_len < e_bytes) {
-                isc_throw(BadKey, "Bad RSA Public Key: short exponent");
-            }
-            if ((key_len - e_bytes) < 64) {
-                isc_throw(BadKey, "Bad RSA Public Key: too short: " <<
-                          (key_len - e_bytes) * 8);
-            }
-            if ((key_len - e_bytes) > 512) {
-                isc_throw(BadKey, "Bad RSA Public Key: too large: " <<
-                          (key_len - e_bytes) * 8);
-            }
-            Botan::BigInt e(p, e_bytes);
-            p += e_bytes;
-            key_len -= e_bytes;
-            Botan::BigInt n(p, key_len);
-            try {
-                pub_.reset(new Botan::RSA_PublicKey(n, e));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "RSA_PublicKey: " << exc.what());
-            }
-        } else if (kind_ == PUBLIC) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Public Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((kind_ == CERT) && (key_format == ASN1)) {
-            // X.509 Public Key Certificate
-            const Botan::byte* keyin =
-                reinterpret_cast<const Botan::byte*>(key);
-            Botan::DataSource_Memory source(keyin, key_len);
-            try {
-                x509_.reset(new Botan::X509_Certificate(source));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "X509_Certificate: " << exc.what());
-            }
-            const Botan::AlgorithmIdentifier
-                sig_algo(x509_->signature_algorithm());
-            if (hash_ == MD5) {
-                const Botan::AlgorithmIdentifier
-                    rsa_md5("1.2.840.113549.1.1.4",
-                            Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-                if (sig_algo != rsa_md5) {
-                    x509_.reset();
-                    isc_throw(BadKey, "Require a RSA MD5 certificate");
-                }
-            } else if (hash_ == SHA1) {
-                const Botan::AlgorithmIdentifier
-                    rsa_sha1("1.2.840.113549.1.1.5",
-                             Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-                if (sig_algo != rsa_sha1) {
-                    x509_.reset();
-                    isc_throw(BadKey, "Require a RSA SHA1 certificate");
-                }
-            } else if (hash_ == SHA224) {
-                const Botan::AlgorithmIdentifier
-                    rsa_sha224("1.2.840.113549.1.1.14",
-                               Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-                if (sig_algo != rsa_sha224) {
-                    x509_.reset();
-                    isc_throw(BadKey, "Require a RSA SHA224 certificate");
-                }
-            } else if (hash_ == SHA256) {
-                const Botan::AlgorithmIdentifier
-                    rsa_sha256("1.2.840.113549.1.1.11",
-                               Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-                if (sig_algo != rsa_sha256) {
-                    x509_.reset();
-                    isc_throw(BadKey, "Require a RSA SHA256 certificate");
-                }
-            } else if (hash_ == SHA384) {
-                const Botan::AlgorithmIdentifier
-                    rsa_sha384("1.2.840.113549.1.1.12",
-                               Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-                if (sig_algo != rsa_sha384) {
-                    x509_.reset();
-                    isc_throw(BadKey, "Require a RSA SHA384 certificate");
-                }
-            } else if (hash_ == SHA512) {
-                const Botan::AlgorithmIdentifier
-                    rsa_sha512("1.2.840.113549.1.1.13",
-                               Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-                if (sig_algo != rsa_sha512) {
-                    x509_.reset();
-                    isc_throw(BadKey, "Require a RSA SHA512 certificate");
-                }
-            } else {
-                x509_.reset();
-                isc_throw(UnsupportedAlgorithm,
-                          "Bad hash algorithm for certificate: " <<
-                          static_cast<int>(hash_));
-            }
-            Botan::Public_Key* key = x509_->subject_public_key();
-            if (key->algo_name().compare("RSA") != 0) {
-                delete key;
-                x509_.reset();
-                isc_throw(BadKey, "not a RSA Certificate");
-            }
-            pub_.reset(dynamic_cast<Botan::RSA_PublicKey*>(key));
-            if (!pub_) {
-                delete key;
-                x509_.reset();
-                isc_throw(LibraryError, "dynamic_cast");
-            }
-        } else if (kind_ == CERT) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown Certificate format: " <<
-                      static_cast<int>(key_format));
-        } else {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Key kind: " <<
-                      static_cast<int>(kind_));
-        }
-
-        if (kind_ == PRIVATE) {
-            try {
-                if (!pub_) {
-                    pub_.reset(new Botan::RSA_PublicKey(priv_->get_n(),
-                                                        priv_->get_e()));
-                }
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "priv to pub: " << exc.what());
-            }
-            try {
-                signer_.reset(new Botan::PK_Signer(*priv_, emsa));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "PK_Signer: " << exc.what());
-            }
-        } else {
-            try {
-                verifier_.reset(new Botan::PK_Verifier(*pub_, emsa));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "PK_Verifier: " << exc.what());
-            }
-        }
-    }
-
-    /// @brief Constructor from a key file with password,
-    ///        asym and hash algorithm, key kind and key binary format
-    ///
-    /// See constructor of the @ref isc::cryptolink::Asym class for details.
-    ///
-    /// @param filename       The key file name/path
-    /// @param password       The PKCS#8 password
-    /// @param hash_algorithm The hash algorithm
-    /// @param key_kind       The key kind
-    /// @param key_format     The key binary format
-    RsaAsymImpl(const std::string& filename,
-                const std::string& password,
-                const HashAlgorithm hash_algorithm,
-                const AsymKeyKind key_kind,
-                const AsymFormat key_format) {
-        algo_ = RSA_;
-        hash_ = hash_algorithm;
-        kind_ = key_kind;
-        std::string hash = btn::getHashAlgorithmName(hash_);
-        if (hash.compare("Unknown") == 0) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown hash algorithm: " <<
-                      static_cast<int>(hash_));
-        }
-        std::string emsa = "EMSA3(" + hash + ")";
-
-        if ((kind_ == PRIVATE) && (key_format == ASN1)) {
-            // PKCS#8 Private Key PEM file
-            Botan::Private_Key* key;
-            Botan::AutoSeeded_RNG rng;
-            try {
-                key = Botan::PKCS8::load_key(filename, rng, password);
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "PKCS8::load_key: " << exc.what());
-            }
-            if (key->algo_name().compare("RSA") != 0) {
-                delete key;
-                isc_throw(BadKey, "not a RSA Private Key");
-            }
-            priv_.reset(dynamic_cast<Botan::RSA_PrivateKey*>(key));
-            if (!priv_) {
-                delete key;
-                isc_throw(LibraryError, "dynamic_cast");
-            }
-        } else if ((kind_ == PRIVATE) && (key_format == DNS)) {
-            // bind9 .private file
-            // warn when password not empty
-            if ((hash_ != MD5) && (hash_ != SHA1) &&
-                (hash_ != SHA256) && (hash_ != SHA512)) {
-                isc_throw(UnsupportedAlgorithm,
-                          "Not compatible hash algorithm: " <<
-                          static_cast<int>(hash_));
-            }
-            std::ifstream fp(filename.c_str(), std::ios::in);
-            if (!fp.is_open()) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            bool got_algorithm = false;
-            bool got_modulus = false;
-            bool got_pub_exponent = false;
-            bool got_priv_exponent = false;
-            bool got_prime1 = false;
-            bool got_prime2 = false;
-            Botan::BigInt n;
-            Botan::BigInt e;
-            Botan::BigInt d;
-            Botan::BigInt p;
-            Botan::BigInt q;
-            while (fp.good()) {
-                std::string line;
-                getline(fp, line);
-                if (line.find("Algorithm:") == 0) {
-                    if (got_algorithm) {
-                        fp.close();
-                        isc_throw(BadKey, "Two Algorithm entries");
-                    }
-                    got_algorithm = true;
-                    std::string value = line.substr(strlen("Algorithm:") + 1,
-                                                    std::string::npos);
-                    int alg = std::atoi(value.c_str());
-                    if (alg == 1) {
-                        // RSAMD5
-                        if (hash_ != MD5) {
-                            fp.close();
-                            isc_throw(BadKey, "Require a RSA MD5 key");
-                        }
-                    } else if ((alg == 5) || (alg == 7)) {
-                        // RSASHA1 or RSASHA1-NSEC3-SHA1
-                        if (hash_ != SHA1) {
-                            fp.close();
-                            isc_throw(BadKey, "Require a RSA SHA1 key");
-                        }
-                    } else if (alg == 8) {
-                        // RSASHA256
-                        if (hash_ != SHA256) {
-                            fp.close();
-                            isc_throw(BadKey, "Require a RSA SHA256 key");
-                        }
-                    } else if (alg == 10) {
-                        // RSASHA512
-                        if (hash_ != SHA512) {
-                            fp.close();
-                            isc_throw(BadKey, "Require a RSA SHA512 key");
-                        }
-                    } else {
-                        fp.close();
-                        isc_throw(BadKey, "Bad Algorithm: " << alg);
-                    }
-                } else if (line.find("Modulus:") == 0) {
-                    if (got_modulus) {
-                        fp.close();
-                        isc_throw(BadKey, "Two Modulus entries");
-                    }
-                    got_modulus = true;
-                    std::string value = line.substr(strlen("Modulus:") + 1,
-                                                    std::string::npos);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        fp.close();
-                        isc_throw(BadKey, "Modulus: " << exc.what());
-                    }
-                    n = Botan::BigInt(&bin[0], bin.size());
-              } else if (line.find("PublicExponent:") == 0) {
-                    if (got_pub_exponent) {
-                        fp.close();
-                        isc_throw(BadKey, "Two PublicExponent entries");
-                    }
-                    got_pub_exponent = true;
-                    std::string value =
-                        line.substr(strlen("PublicExponent:") + 1,
-                                    std::string::npos);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        fp.close();
-                        isc_throw(BadKey, "PublicExponent: " << exc.what());
-                    }
-                    e = Botan::BigInt(&bin[0], bin.size());
-                } else if (line.find("PrivateExponent:") == 0) {
-                    if (got_priv_exponent) {
-                        fp.close();
-                        isc_throw(BadKey, "Two PrivateExponent entries");
-                    }
-                    got_priv_exponent = true;
-                    std::string value =
-                        line.substr(strlen("PrivateExponent:") + 1,
-                                    std::string::npos);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        fp.close();
-                        isc_throw(BadKey, "PrivateExponent: " << exc.what());
-                    }
-                    d = Botan::BigInt(&bin[0], bin.size());
-                } else if (line.find("Prime1:") == 0) {
-                    if (got_prime1) {
-                        fp.close();
-                        isc_throw(BadKey, "Two Prime1 entries");
-                    }
-                    got_prime1 = true;
-                    std::string value = line.substr(strlen("Prime1:") + 1,
-                                                    std::string::npos);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        fp.close();
-                        isc_throw(BadKey, "Prime1: " << exc.what());
-                    }
-                    p = Botan::BigInt(&bin[0], bin.size());
-                } else if (line.find("Prime2:") == 0) {
-                    if (got_prime2) {
-                        fp.close();
-                        isc_throw(BadKey, "Two Prime2 entries");
-                    }
-                    got_prime2 = true;
-                    std::string value = line.substr(strlen("Prime2:") + 1,
-                                                    std::string::npos);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        fp.close();
-                        isc_throw(BadKey, "Prime2: " << exc.what());
-                    }
-                    q = Botan::BigInt(&bin[0], bin.size());
-                }
-            }
-            fp.close();
-            if (!got_algorithm) {
-                isc_throw(BadKey, "Missing Algorithm entry");
-            }
-            if (!got_modulus) {
-                isc_throw(BadKey, "Missing Modulus entry");
-            }
-            if (!got_pub_exponent) {
-                isc_throw(BadKey, "Missing PublicExponent entry");
-            }
-            if (!got_priv_exponent) {
-                isc_throw(BadKey, "Missing PrivateExponent entry");
-            }
-            if (!got_prime1) {
-                isc_throw(BadKey, "Missing Prime1 entry");
-            }
-            if (!got_prime2) {
-                isc_throw(BadKey, "Missing Prime2 entry");
-            }
-            Botan::AutoSeeded_RNG rng;
-            try {
-                priv_.reset(new Botan::RSA_PrivateKey(rng, p, q, e, d, n));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "RSA_PrivateKey" << exc.what());
-            }
-        } else if (kind_ == PRIVATE) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Private Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((kind_ == PUBLIC) && (key_format == ASN1)) {
-            // SubjectPublicKeyInfo PEM file
-            // warn when password not empty
-            Botan::Public_Key* key;
-            try {
-                key = Botan::X509::load_key(filename);
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "X509::load_key: " << exc.what());
-            }
-            if (key->algo_name().compare("RSA") != 0) {
-                delete key;
-                isc_throw(BadKey, "not a RSA Public Key");
-            }
-            pub_.reset(dynamic_cast<Botan::RSA_PublicKey*>(key));
-            if (!pub_) {
-                delete key;
-                isc_throw(LibraryError, "dynamic_cast");
-            }
-        } else if ((kind_ == PUBLIC) && (key_format == DNS)) {
-            // bind9 .key file (RDATA)
-            // warn when password not empty
-            if ((hash_ != MD5) && (hash_ != SHA1) &&
-                (hash_ != SHA256) && (hash_ != SHA512)) {
-                isc_throw(UnsupportedAlgorithm,
-                          "Not compatible hash algorithm: " <<
-                          static_cast<int>(hash_));
-            }
-            std::ifstream fp(filename.c_str(), std::ios::in);
-            if (!fp.is_open()) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            std::string line;
-            bool found = false;
-            while (fp.good()) {
-                getline(fp, line);
-                if (line.empty() || (line[0] == ';')) {
-                    continue;
-                }
-                if (line.find("DNSKEY") == std::string::npos) {
-                    continue;
-                }
-                found = true;
-                if (line[line.size() - 1] == '\n') {
-                    line.erase(line.size() - 1);
-                }
-                break;
-            }
-            fp.close();
-            if (!found) {
-                isc_throw(BadKey, "Can't find a DNSKEY");
-            }
-            const std::string b64 =
-                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
-                "ghijklmnopqrstuvwxyz0123456789+/=";
-            const std::string value = line.substr(line.find_last_not_of(b64));
-            std::vector<uint8_t> bin;
-            try {
-                util::encode::decodeBase64(value, bin);
-            } catch (const BadValue& exc) {
-               isc_throw(BadKey, "Can't decode base64: " << exc.what());
-            }
-            size_t key_len = bin.size();
-            const uint8_t* p = &bin[0];
-            size_t e_bytes = *p++;
-            --key_len;
-            if (e_bytes == 0) {
-                if (key_len < 2) {
-                    isc_throw(BadKey,
-                              "Bad RSA Public Key: short exponent length");
-                }
-                e_bytes = (*p++) << 8;
-                e_bytes += *p++;
-                key_len -= 2;
-            }
-            if (key_len < e_bytes) {
-                isc_throw(BadKey, "Bad RSA Public Key: short exponent");
-            }
-            if ((key_len - e_bytes) < 64) {
-                isc_throw(BadKey, "Bad RSA Public Key: too short: " <<
-                          (key_len - e_bytes) * 8);
-            }
-            if ((key_len - e_bytes) > 512) {
-                isc_throw(BadKey, "Bad RSA Public Key: too large: " <<
-                          (key_len - e_bytes) * 8);
-            }
-            Botan::BigInt e(p, e_bytes);
-            p += e_bytes;
-            key_len -= e_bytes;
-            Botan::BigInt n(p, key_len);
-            try {
-                pub_.reset(new Botan::RSA_PublicKey(n, e));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "RSA_PublicKey: " << exc.what());
-            }
-        } else if (kind_ == PUBLIC) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Public Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((kind_ == CERT) && (key_format == ASN1)) {
-            // X.509 Public Key Certificate PEM file
-            // warn when password not empty
-            try {
-                x509_.reset(new Botan::X509_Certificate(filename));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "X509_Certificate: " << exc.what());
-            }
-            const Botan::AlgorithmIdentifier
-                sig_algo(x509_->signature_algorithm());
-            if (hash_ == MD5) {
-                const Botan::AlgorithmIdentifier
-                    rsa_md5("1.2.840.113549.1.1.4",
-                            Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-                if (sig_algo != rsa_md5) {
-                    x509_.reset();
-                    isc_throw(BadKey, "Require a RSA MD5 certificate");
-                }
-            } else if (hash_ == SHA1) {
-                const Botan::AlgorithmIdentifier
-                    rsa_sha1("1.2.840.113549.1.1.5",
-                             Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-                if (sig_algo != rsa_sha1) {
-                    x509_.reset();
-                    isc_throw(BadKey, "Require a RSA SHA1 certificate");
-                }
-            } else if (hash_ == SHA224) {
-                const Botan::AlgorithmIdentifier
-                    rsa_sha224("1.2.840.113549.1.1.14",
-                               Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-                if (sig_algo != rsa_sha224) {
-                    x509_.reset();
-                    isc_throw(BadKey, "Require a RSA SHA224 certificate");
-                }
-            } else if (hash_ == SHA256) {
-                const Botan::AlgorithmIdentifier
-                    rsa_sha256("1.2.840.113549.1.1.11",
-                               Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-                if (sig_algo != rsa_sha256) {
-                    x509_.reset();
-                    isc_throw(BadKey, "Require a RSA SHA256 certificate");
-                }
-            } else if (hash_ == SHA384) {
-                const Botan::AlgorithmIdentifier
-                    rsa_sha384("1.2.840.113549.1.1.12",
-                               Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-                if (sig_algo != rsa_sha384) {
-                    x509_.reset();
-                    isc_throw(BadKey, "Require a RSA SHA384 certificate");
-                }
-            } else if (hash_ == SHA512) {
-                const Botan::AlgorithmIdentifier
-                    rsa_sha512("1.2.840.113549.1.1.13",
-                               Botan::AlgorithmIdentifier::USE_NULL_PARAM);
-                if (sig_algo != rsa_sha512) {
-                    x509_.reset();
-                    isc_throw(BadKey, "Require a RSA SHA512 certificate");
-                }
-            } else {
-                x509_.reset();
-                isc_throw(UnsupportedAlgorithm,
-                          "Bad hash algorithm for certificate: " <<
-                          static_cast<int>(hash_));
-            }
-            Botan::Public_Key* key;
-            try {
-                key = x509_->subject_public_key();
-            } catch (const std::exception& exc) {
-                x509_.reset();
-                isc_throw(BadKey, "subject_public_key: " << exc.what());
-            }
-            if (key->algo_name().compare("RSA") != 0) {
-                delete key;
-                x509_.reset();
-                isc_throw(BadKey, "not a RSA Public Key");
-            }
-            pub_.reset(dynamic_cast<Botan::RSA_PublicKey*>(key));
-            if (!pub_) {
-                delete key;
-                x509_.reset();
-                isc_throw(LibraryError, "dynamic_cast");
-            }
-        } else if (kind_ == CERT) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown Public Key Certificate format: " <<
-                      static_cast<int>(key_format));
-        } else {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Key kind: " <<
-                      static_cast<int>(kind_));
-        }
-
-        if (kind_ == PRIVATE) {
-            try {
-                if (!pub_) {
-                    pub_.reset(new Botan::RSA_PublicKey(priv_->get_n(),
-                                                        priv_->get_e()));
-                }
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "priv to pub: " << exc.what());
-            }
-            try {
-                signer_.reset(new Botan::PK_Signer(*priv_, emsa));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "PK_Signer: " << exc.what());
-            }
-        } else {
-            try {
-                verifier_.reset(new Botan::PK_Verifier(*pub_, emsa));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "PK_Verifier: " << exc.what());
-            }
-        }
-    }
-
-    /// @brief Destructor
-    ~RsaAsymImpl() { }
-
-    /// @brief Returns the AsymAlgorithm of the object
-    AsymAlgorithm getAsymAlgorithm() const {
-        return (algo_);
-    }
-
-    /// @brief Returns the HashAlgorithm of the object
-    HashAlgorithm getHashAlgorithm() const {
-        return (hash_);
-    }
-
-    /// @brief Returns the AsymKeyKind of the object
-    AsymKeyKind getAsymKeyKind() const {
-        return (kind_);
-    }
-
-    /// @brief Returns the key size in bits
-    ///
-    size_t getKeySize() const {
-        if (kind_ == PRIVATE) {
-            return (priv_->get_n().bits());
-        } else {
-            return (pub_->get_n().bits());
-        }
-    }
-
-    /// @brief Returns the output size of the signature
-    ///
-    /// \param sig_format The signature binary format
-    size_t getSignatureLength(const AsymFormat sig_format) const {
-        switch (sig_format) {
-        case BASIC:
-        case ASN1:
-        case DNS:
-            // In all cases a big integer of the size of n
-            if (kind_ == PRIVATE) {
-                return (priv_->get_n().bytes());
-            } else {
-                return (pub_->get_n().bytes());
-            }
-        default:
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Signature format: " <<
-                      static_cast<int>(sig_format));
-        }
-    }           
-
-    /// @brief Add data to digest
-    ///
-    /// See @ref isc::cryptolink::AsymBase::update() for details.
-    void update(const void* data, const size_t len) {
-        try {
-            if (kind_ == PRIVATE) {
-                signer_->update(
-                    reinterpret_cast<const Botan::byte*>(data), len);
-            } else {
-                verifier_->update(
-                    reinterpret_cast<const Botan::byte*>(data), len);
-            }            
-        } catch (const std::exception& exc) {
-            isc_throw(LibraryError, "update: " << exc.what());
-        }
-    }
-
-    /// @brief Calculate the final signature
-    ///
-    /// See @ref isc::cryptolink::AsymBase::sign() for details.
-    void sign(isc::util::OutputBuffer& result, size_t len,
-              const AsymFormat) {
-        try {
-            Botan::SecureVector<Botan::byte> b_result;
-            Botan::AutoSeeded_RNG rng;
-            b_result = signer_->signature(rng);
-            if (len > b_result.size()) {
-                len = b_result.size();
-            }
-            result.writeData(b_result.begin(), len);
-        } catch (const std::exception& exc) {
-            isc_throw(LibraryError, "signature: " << exc.what());
-        }
-    }
-
-    /// @brief Calculate the final signature
-    ///
-    /// See @ref isc::cryptolink::AsymBase::sign() for details.
-    void sign(void* result, size_t len, const AsymFormat sig_format) {
-        try {
-            Botan::SecureVector<Botan::byte> b_result;
-            Botan::AutoSeeded_RNG rng;
-            b_result = signer_->signature(rng);
-            size_t output_size = getSignatureLength(sig_format);
-            if (output_size > len) {
-                output_size = len;
-            }
-            std::memcpy(result, b_result.begin(), output_size);
-        } catch (const std::exception& exc) {
-            isc_throw(LibraryError, "signature: " << exc.what());
-        }
-    }
-
-    /// @brief Calculate the final signature
-    ///
-    /// See @ref isc::cryptolink::AsymBase::sign() for details.
-    std::vector<uint8_t> sign(size_t len, const AsymFormat) {
-        try {
-            Botan::SecureVector<Botan::byte> b_result;
-            Botan::AutoSeeded_RNG rng;
-            b_result = signer_->signature(rng);
-            if (len > b_result.size()) {
-                return (std::vector<uint8_t>(b_result.begin(), b_result.end()));
-            } else {
-                return (std::vector<uint8_t>(b_result.begin(), &b_result[len]));
-            }
-        } catch (const std::exception& exc) {
-            isc_throw(LibraryError, "signature: " << exc.what());
-        }
-    }
-
-    /// @brief Verify an existing signature
-    ///
-    /// See @ref isc::cryptolink::AsymBase::verify() for details.
-    bool verify(const void* sig, size_t len, const AsymFormat sig_format) {
-        size_t size = getSignatureLength(sig_format);
-        if (len != size) {
-            return false;
-        }
-        const Botan::byte* sigbuf = reinterpret_cast<const Botan::byte*>(sig);
-        try {
-            return verifier_->check_signature(sigbuf, len);
-        } catch (const std::exception& exc) {
-            isc_throw(LibraryError, "check_signature: " << exc.what());
-        }
-    }
-
-    /// \brief Clear the crypto state and go back to the initial state
-    /// (must be called before reusing an Asym object)
-    void clear() {
-        std::string hash = btn::getHashAlgorithmName(hash_);
-        if (hash.compare("Unknown") == 0) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown hash algorithm: " <<
-                      static_cast<int>(hash_));
-        }
-        std::string emsa = "EMSA3(" + hash + ")";
-        if (kind_ == PRIVATE) {
-            try {
-                signer_.reset(new Botan::PK_Signer(*priv_, emsa));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "PK_Signer: " << exc.what());
-            }
-        } else {
-            try {
-                verifier_.reset(new Botan::PK_Verifier(*pub_, emsa));
-            } catch (const std::exception& exc) {
-                isc_throw(BadKey, "PK_Verifier: " << exc.what());
-            }
-        }
-    }
-
-    /// @brief Export the key value (binary)
-    ///
-    /// See @ref isc::cryptolink::AsymBase::exportkey() for details
-    std::vector<uint8_t> exportkey(const AsymKeyKind key_kind,
-                                   const AsymFormat key_format) const {
-        if ((key_kind == PRIVATE) && (key_format == BASIC)) {
-            // PKCS#1 Private Key
-            if (kind_ != PRIVATE) {
-                isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
-            }
-            Botan::MemoryVector<Botan::byte> der;
-            try {
-                der = priv_->pkcs8_private_key();
-            } catch (const std::exception& exc) {
-                isc_throw(LibraryError, "pkcs8_private_key: " << exc.what());
-            }
-            return std::vector<uint8_t>(der.begin(), der.end());
-        } else if (key_kind == PRIVATE) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Private Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((key_kind == PUBLIC) && (key_format == BASIC)) {
-            // PKCS#1 Public Key
-            Botan::MemoryVector<Botan::byte> der;
-            try {
-                der = pub_->x509_subject_public_key();
-            } catch (const std::exception& exc) {
-                isc_throw(LibraryError,
-                          "x509_subject_public_key: "
-                          << exc.what());
-            }
-            return std::vector<uint8_t>(der.begin(), der.end());
-        } else if ((key_kind == PUBLIC) && (key_format == ASN1)) {
-            // SubjectPublicKeyInfo
-            Botan::MemoryVector<Botan::byte> ber;
-            try {
-                ber = Botan::X509::BER_encode(*pub_);
-            } catch (const std::exception& exc) {
-                isc_throw(LibraryError, "X509::BER_encode: " << exc.what());
-            }
-            return std::vector<uint8_t>(ber.begin(), ber.end());
-        } else if ((key_kind == PUBLIC) && (key_format == DNS)) {
-            // RFC 3110 DNS wire format
-            size_t e_bytes = pub_->get_e().bytes();
-            size_t mod_bytes = pub_->get_n().bytes();
-            size_t x_bytes = 1;
-            if (e_bytes >= 256) {
-                x_bytes += 2;
-            }
-            std::vector<uint8_t> rdata(x_bytes + e_bytes + mod_bytes);
-            if (e_bytes < 256) {
-                rdata[0] = e_bytes;
-            } else {
-                rdata[0] = 0;
-                rdata[1] = (e_bytes >> 8) & 0xff;
-                rdata[2] = e_bytes & 0xff;
-            }
-            pub_->get_e().binary_encode(&rdata[x_bytes]);
-            pub_->get_n().binary_encode(&rdata[x_bytes + e_bytes]);
-            return rdata;
-        } else if (key_kind == PUBLIC) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Public Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((key_kind == CERT) && (key_format == ASN1)) {
-            // X.509 Public Key Certificate
-            if (kind_ != CERT) {
-                isc_throw(UnsupportedAlgorithm, "Have no Certificate");
-            }
-            Botan::MemoryVector<Botan::byte> ber;
-            try {
-                ber = x509_->BER_encode();
-            } catch (const std::exception& exc) {
-                isc_throw(LibraryError, "BER_encode" << exc.what());
-            }
-            return std::vector<uint8_t>(ber.begin(), ber.end());
-        } else if (key_kind == CERT) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown Certificate format: " <<
-                      static_cast<int>(key_format));
-        } else {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Key kind: " <<
-                      static_cast<int>(key_kind));
-        }
-    }
-
-    /// @brief Export the key value (file)
-    ///
-    /// See @ref isc::cryptolink::AsymBase::exportkey() for details
-    void exportkey(const std::string& filename,
-                   const std::string& password,
-                   const AsymKeyKind key_kind,
-                   const AsymFormat key_format) const {
-        if ((key_kind == PRIVATE) && (key_format == ASN1)) {
-            // PKCS#8 Private Key PEM file
-            std::string pem;
-            Botan::AutoSeeded_RNG rng;
-            try {
-                pem = Botan::PKCS8::PEM_encode(*priv_, rng,
-                                               password, "AES-128/CBC");
-            } catch (const std::exception& exc) {
-                isc_throw(LibraryError, "PKCS8::PEM_encode: " << exc.what());
-            }
-            std::ofstream fp(filename.c_str(),
-                             std::ofstream::out | std::ofstream::trunc);
-            if (fp.is_open()) {
-                fp.write(pem.c_str(), pem.size());
-                fp.close();
-            } else {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-        } else if ((key_kind == PRIVATE) && (key_format == DNS)) {
-            //  bind9 .private file
-            if (kind_ != PRIVATE) {
-                isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
-            }
-            if ((hash_ != MD5) && (hash_ != SHA1) &&
-                (hash_ != SHA256) && (hash_ != SHA512)) {
-                isc_throw(UnsupportedAlgorithm,
-                          "Not compatible hash algorithm: " <<
-                          static_cast<int>(hash_));
-            }
-            std::ofstream fp(filename.c_str(),
-                             std::ofstream::out | std::ofstream::trunc);
-            if (!fp.is_open()) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            fp << "Private-key-format: v1.2\n";
-            if (hash_ == MD5) {
-                fp << "Algorithm: 1 (RSA)\n";
-            } else if (hash_ == SHA1) {
-                fp << "Algorithm: 5 (RSASHA1)\n";
-            } else if (hash_ == SHA256) {
-                fp << "Algorithm: 8 (RSASHA256)\n";
-            } else if (hash_ == SHA512) {
-                fp << "Algorithm: 10 (RSASHA512)\n";
-            }
-            std::vector<uint8_t> bin;
-            bin.resize(priv_->get_n().bytes());
-            priv_->get_n().binary_encode(&bin[0]);
-            fp << "Modulus: " << util::encode::encodeBase64(bin) << '\n';
-            bin.resize(priv_->get_e().bytes());
-            priv_->get_e().binary_encode(&bin[0]);
-            fp << "PublicExponent: " <<
-                util::encode::encodeBase64(bin) << '\n';
-            bin.resize(priv_->get_d().bytes());
-            priv_->get_d().binary_encode(&bin[0]);
-            fp << "PrivateExponent: " <<
-                util::encode::encodeBase64(bin) << '\n';
-            bin.resize(priv_->get_p().bytes());
-            priv_->get_p().binary_encode(&bin[0]);
-            fp << "Prime1: " << util::encode::encodeBase64(bin) << '\n';
-            bin.resize(priv_->get_q().bytes());
-            priv_->get_q().binary_encode(&bin[0]);
-            fp << "Prime2: " << util::encode::encodeBase64(bin) << '\n';
-            bin.resize(priv_->get_d1().bytes());
-            priv_->get_d1().binary_encode(&bin[0]);
-            fp << "Exponent1: " << util::encode::encodeBase64(bin) << '\n';
-            bin.resize(priv_->get_d2().bytes());
-            priv_->get_d2().binary_encode(&bin[0]);
-            fp << "Exponent2: " << util::encode::encodeBase64(bin) << '\n';
-            bin.resize(priv_->get_c().bytes());
-            priv_->get_c().binary_encode(&bin[0]);
-            fp << "Coefficient: " << util::encode::encodeBase64(bin) << '\n';
-            fp.close();
-        } else if (key_kind == PRIVATE) {
-            if (kind_ != PRIVATE) {
-                isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
-            }
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Private Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((key_kind == PUBLIC) && (key_format == ASN1)) {
-            // SubjectPublicKeyInfo PEM file
-            // warn when password not empty
-            std::string pem;
-            try {
-                pem = Botan::X509::PEM_encode(*pub_);
-            } catch (const std::exception& exc) {
-                isc_throw(LibraryError, "X509::PEM_encode: " << exc.what());
-            }
-            std::ofstream fp(filename.c_str(),
-                             std::ofstream::out | std::ofstream::trunc);
-            if (fp.is_open()) {
-                fp.write(pem.c_str(), pem.size());
-                fp.close();
-            } else {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-        }  else if ((key_kind == PUBLIC) && (key_format == DNS)) {
-            // bind9 .key file (RDATA)
-            // warn when password not empty
-            std::vector<uint8_t> bin = exportkey(key_kind, key_format);
-            std::ofstream fp(filename.c_str(),
-                             std::ofstream::out | std::ofstream::trunc);
-            if (!fp.is_open()) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            fp << "; DNSKEY RDATA: " <<
-                util::encode::encodeBase64(bin) << '\n';
-            fp.close();
-        } else if (key_kind == PUBLIC) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Public Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((key_kind == CERT) && (key_format == ASN1)) {
-            // Public Key Certificate PEM file
-            // warn when password not empty
-            if (!x509_) {
-                isc_throw(UnsupportedAlgorithm, "Have no Certificate");
-            }
-            std::string pem;
-            try {
-                pem = x509_->PEM_encode();
-            } catch (const std::exception& exc) {
-                isc_throw(LibraryError, "PEM_encode: " << exc.what());
-            }
-            std::ofstream fp(filename.c_str(),
-                             std::ofstream::out | std::ofstream::trunc);
-            if (fp.is_open()) {
-                fp.write(pem.c_str(), pem.size());
-                fp.close();
-            } else {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-        } else if (key_kind == CERT) {
-            if (!x509_) {
-                isc_throw(UnsupportedAlgorithm, "Have no Certificate");
-            }
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown Certificate format: " <<
-                      static_cast<int>(key_format));
-        } else {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Key kind: " <<
-                      static_cast<int>(key_kind));
-        }
-    }
-
-    /// @brief Check the validity
-    ///
-    /// See @ref isc::cryptolink::AsymBase::validate() for details
-    bool validate() const {
-        Botan::AutoSeeded_RNG rng;
-        Botan::X509_Store store;
-        Botan::X509_Code status;
-        switch (kind_) {
-        case PUBLIC:
-            // what to do?
-            try {
-                return pub_->check_key(rng, true);
-            } catch (const std::exception& exc) {
-                isc_throw(LibraryError, "check_key: " << exc.what());
-            }
-        case PRIVATE:
-            try {
-                return priv_->check_key(rng, true);
-            } catch (const std::exception& exc) {
-                isc_throw(LibraryError, "check_key: " << exc.what());
-            }
-        case CERT:
-            store.add_cert(*x509_, true);
-            status = store.validate_cert(*x509_);
-            if (status == Botan::VERIFIED) {
-                return true;
-            }
-            return false;
-        default:
-            return false;
-        }
-    }
-
-    /// @brief Compare two keys
-    ///
-    /// See @ref isc::cryptolink::Asym::compare() for details
-    bool compare(const RsaAsymImpl* other, const AsymKeyKind key_kind) const {
-        if (!other || (other->algo_ != RSA_)) {
-            return false;
-        }
-        Botan::BigInt e, n;
-        switch (key_kind) {
-        case CERT:
-            // Special case for cert - cert
-            if ((kind_ == CERT) && (other->kind_ == CERT)) {
-                return (*x509_ == *other->x509_);
-            }
-            // At least one should be a cert
-            if ((kind_ != CERT) && (other->kind_ != CERT)) {
-                return false;
-            }
-            // For all other cases just compare public keys
-            // Falls into
-        case PUBLIC:
-            if (kind_ == PRIVATE) {
-                e = priv_->get_e();
-                n = priv_->get_n();;
-            } else if ((kind_ == PUBLIC) || (kind_ == CERT)) {
-                e = pub_->get_e();
-                n = pub_->get_n();
-            } else {
-                return false;
-            }
-            if (other->kind_ == PRIVATE) {
-                return ((e == other->priv_->get_e()) &&
-                        (n == other->priv_->get_n()));
-            } else if ((other->kind_ == PUBLIC) || (other->kind_ == CERT)) {
-                return ((e == other->pub_->get_e()) &&
-                        (n == other->pub_->get_n()));
-            } else {
-                return false;
-            }
-        case PRIVATE:
-            if ((kind_ != PRIVATE) || (other->kind_ != PRIVATE)) {
-                return false;
-            }
-            // If public keys match so private too
-            return ((priv_->get_e() == other->priv_->get_e()) &&
-                    (priv_->get_n() == other->priv_->get_n()));
-        default:
-            return false;
-        }
-    }
-
-private:
-    /// @brief The asymmetrical cryptography algorithm
-    AsymAlgorithm algo_;
-    /// @brief The hash algorithm
-    HashAlgorithm hash_;
-    /// @brief The key kind
-    AsymKeyKind kind_;
-    /// @brief The protected pointer to the Botan private key
-    boost::scoped_ptr<Botan::RSA_PrivateKey> priv_;
-    /// @brief The protected pointer to the Botan public key
-    boost::scoped_ptr<Botan::RSA_PublicKey> pub_;
-    /// @brief The protected pointer to the Botan certificate
-    boost::scoped_ptr<Botan::X509_Certificate> x509_;
-    /// @brief The protected pointer to the Botan signer
-    boost::scoped_ptr<Botan::PK_Signer> signer_;
-    /// @brief The protected pointer to the Botan verifier
-    boost::scoped_ptr<Botan::PK_Verifier> verifier_;
-};
-
 Asym::Asym(const void* key, size_t key_len,
            const AsymAlgorithm asym_algorithm,
            const HashAlgorithm hash_algorithm,
diff --git a/src/lib/cryptolink/botan_rsa.cc b/src/lib/cryptolink/botan_rsa.cc
new file mode 100644 (file)
index 0000000..e8ac591
--- /dev/null
@@ -0,0 +1,1139 @@
+// Copyright (C) 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cryptolink.h>
+#include <cryptolink/crypto_asym.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <botan/version.h>
+#include <botan/botan.h>
+#include <botan/hash.h>
+#include <botan/oids.h>
+#include <botan/pubkey.h>
+#include <botan/rsa.h>
+#include <botan/x509stor.h>
+
+#include <util/encode/base64.h>
+#include <cryptolink/botan_common.h>
+#include <cryptolink/botan_rsa.h>
+
+#include <cstring>
+#include <fstream>
+
+namespace isc {
+namespace cryptolink {
+
+/// @brief Constructor from a key, asym and hash algorithm,
+///        key kind and key binary format
+RsaAsymImpl::RsaAsymImpl(const void* key, size_t key_len,
+                         const HashAlgorithm hash_algorithm,
+                         const AsymKeyKind key_kind,
+                         const AsymFormat key_format) {
+    algo_ = RSA_;
+    hash_ = hash_algorithm;
+    kind_ = key_kind;
+    std::string hash = btn::getHashAlgorithmName(hash_);
+    if (hash.compare("Unknown") == 0) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown hash algorithm: " << static_cast<int>(hash_));
+    }
+    std::string emsa = "EMSA3(" + hash + ")";
+    if (key_len == 0) {
+        isc_throw(BadKey, "Bad RSA " <<
+                  (kind_ != CERT ? "key" : "cert") << " length: 0");
+    }
+
+    if ((kind_ == PRIVATE) && (key_format == BASIC)) {
+        // PKCS#1 Private Key
+        const Botan::byte* keyin = reinterpret_cast<const Botan::byte*>(key);
+        const Botan::MemoryVector<Botan::byte> ber(keyin, key_len);
+        // rsaEncription OID and NULL parameters
+        const Botan::AlgorithmIdentifier alg_id =
+            Botan::AlgorithmIdentifier("1.2.840.113549.1.1.1",
+                Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+        Botan::AutoSeeded_RNG rng;
+        try {
+            priv_.reset(new Botan::RSA_PrivateKey(alg_id, ber, rng));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "RSA_PrivateKey: " << exc.what());
+        }
+    } else if (kind_ == PRIVATE) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Private Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((kind_ == PUBLIC) && (key_format == BASIC)) {
+        // PKCS#1 Public Key
+        const Botan::byte* keyin = reinterpret_cast<const Botan::byte*>(key);
+        const Botan::MemoryVector<Botan::byte> ber(keyin, key_len);
+        // rsaEncription OID and NULL parameters
+        const Botan::AlgorithmIdentifier alg_id =
+            Botan::AlgorithmIdentifier("1.2.840.113549.1.1.1",
+                Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+        try {
+            pub_.reset(new Botan::RSA_PublicKey(alg_id, ber));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "RSA_PublicKey: " << exc.what());
+        }
+    } else if ((kind_ == PUBLIC) && (key_format == ASN1)) {
+        // SubjectPublicKeyInfo
+        const Botan::byte* keyin = reinterpret_cast<const Botan::byte*>(key);
+        Botan::DataSource_Memory source(keyin, key_len);
+        Botan::Public_Key* key;
+        try {
+            key = Botan::X509::load_key(source);
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "X509::load_key: " << exc.what());
+        }
+        if (key->algo_name().compare("RSA") != 0) {
+            delete key;
+            isc_throw(BadKey, "not a RSA Public Key");
+        }
+        pub_.reset(dynamic_cast<Botan::RSA_PublicKey*>(key));
+        if (!pub_) {
+            delete key;
+            isc_throw(LibraryError, "dynamic_cast");
+        }
+    } else if ((kind_ == PUBLIC) && (key_format == DNS)) {
+        // RFC 3110 DNS wire format
+        // key_len == 0 was already checked
+        const uint8_t* p = reinterpret_cast<const uint8_t*>(key);
+        size_t e_bytes = *p++;
+        --key_len;
+        if (e_bytes == 0) {
+            if (key_len < 2) {
+                isc_throw(BadKey, "Bad RSA Public Key: short exponent length");
+            }
+            e_bytes = (*p++) << 8;
+            e_bytes += *p++;
+            key_len -= 2;
+        }
+        if (key_len < e_bytes) {
+            isc_throw(BadKey, "Bad RSA Public Key: short exponent");
+        }
+        if ((key_len - e_bytes) < 64) {
+            isc_throw(BadKey, "Bad RSA Public Key: too short: " <<
+                      (key_len - e_bytes) * 8);
+        }
+        if ((key_len - e_bytes) > 512) {
+            isc_throw(BadKey, "Bad RSA Public Key: too large: " <<
+                      (key_len - e_bytes) * 8);
+        }
+        Botan::BigInt e(p, e_bytes);
+        p += e_bytes;
+        key_len -= e_bytes;
+        Botan::BigInt n(p, key_len);
+        try {
+            pub_.reset(new Botan::RSA_PublicKey(n, e));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "RSA_PublicKey: " << exc.what());
+        }
+    } else if (kind_ == PUBLIC) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Public Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((kind_ == CERT) && (key_format == ASN1)) {
+        // X.509 Public Key Certificate
+        const Botan::byte* keyin = reinterpret_cast<const Botan::byte*>(key);
+        Botan::DataSource_Memory source(keyin, key_len);
+        try {
+            x509_.reset(new Botan::X509_Certificate(source));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "X509_Certificate: " << exc.what());
+        }
+        const Botan::AlgorithmIdentifier
+            sig_algo(x509_->signature_algorithm());
+        if (hash_ == MD5) {
+            const Botan::AlgorithmIdentifier
+                rsa_md5("1.2.840.113549.1.1.4",
+                        Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+            if (sig_algo != rsa_md5) {
+                x509_.reset();
+                isc_throw(BadKey, "Require a RSA MD5 certificate");
+            }
+        } else if (hash_ == SHA1) {
+            const Botan::AlgorithmIdentifier
+                rsa_sha1("1.2.840.113549.1.1.5",
+                         Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+            if (sig_algo != rsa_sha1) {
+                x509_.reset();
+                isc_throw(BadKey, "Require a RSA SHA1 certificate");
+            }
+        } else if (hash_ == SHA224) {
+            const Botan::AlgorithmIdentifier
+                rsa_sha224("1.2.840.113549.1.1.14",
+                           Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+            if (sig_algo != rsa_sha224) {
+                x509_.reset();
+                isc_throw(BadKey, "Require a RSA SHA224 certificate");
+            }
+        } else if (hash_ == SHA256) {
+            const Botan::AlgorithmIdentifier
+                rsa_sha256("1.2.840.113549.1.1.11",
+                           Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+            if (sig_algo != rsa_sha256) {
+                x509_.reset();
+                isc_throw(BadKey, "Require a RSA SHA256 certificate");
+            }
+        } else if (hash_ == SHA384) {
+            const Botan::AlgorithmIdentifier
+                rsa_sha384("1.2.840.113549.1.1.12",
+                           Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+            if (sig_algo != rsa_sha384) {
+                x509_.reset();
+                isc_throw(BadKey, "Require a RSA SHA384 certificate");
+            }
+        } else if (hash_ == SHA512) {
+            const Botan::AlgorithmIdentifier
+                rsa_sha512("1.2.840.113549.1.1.13",
+                           Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+            if (sig_algo != rsa_sha512) {
+                x509_.reset();
+                isc_throw(BadKey, "Require a RSA SHA512 certificate");
+            }
+        } else {
+            x509_.reset();
+            isc_throw(UnsupportedAlgorithm,
+                      "Bad hash algorithm for certificate: " <<
+                      static_cast<int>(hash_));
+        }
+        Botan::Public_Key* key = x509_->subject_public_key();
+        if (key->algo_name().compare("RSA") != 0) {
+            delete key;
+            x509_.reset();
+            isc_throw(BadKey, "not a RSA Certificate");
+        }
+        pub_.reset(dynamic_cast<Botan::RSA_PublicKey*>(key));
+        if (!pub_) {
+            delete key;
+            x509_.reset();
+            isc_throw(LibraryError, "dynamic_cast");
+        }
+    } else if (kind_ == CERT) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown Certificate format: " <<
+                  static_cast<int>(key_format));
+    } else {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Key kind: " << static_cast<int>(kind_));
+    }
+
+    if (kind_ == PRIVATE) {
+        try {
+            if (!pub_) {
+                pub_.reset(new Botan::RSA_PublicKey(priv_->get_n(),
+                                                    priv_->get_e()));
+            }
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "priv to pub: " << exc.what());
+        }
+        try {
+            signer_.reset(new Botan::PK_Signer(*priv_, emsa));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "PK_Signer: " << exc.what());
+        }
+    } else {
+        try {
+            verifier_.reset(new Botan::PK_Verifier(*pub_, emsa));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "PK_Verifier: " << exc.what());
+        }
+    }
+}
+
+/// @brief Constructor from a key file with password,
+///        asym and hash algorithm, key kind and key binary format
+RsaAsymImpl::RsaAsymImpl(const std::string& filename,
+                         const std::string& password,
+                         const HashAlgorithm hash_algorithm,
+                         const AsymKeyKind key_kind,
+                         const AsymFormat key_format) {
+    algo_ = RSA_;
+    hash_ = hash_algorithm;
+    kind_ = key_kind;
+    std::string hash = btn::getHashAlgorithmName(hash_);
+    if (hash.compare("Unknown") == 0) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown hash algorithm: " << static_cast<int>(hash_));
+    }
+    std::string emsa = "EMSA3(" + hash + ")";
+
+    if ((kind_ == PRIVATE) && (key_format == ASN1)) {
+        // PKCS#8 Private Key PEM file
+        Botan::Private_Key* key;
+        Botan::AutoSeeded_RNG rng;
+        try {
+            key = Botan::PKCS8::load_key(filename, rng, password);
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "PKCS8::load_key: " << exc.what());
+        }
+        if (key->algo_name().compare("RSA") != 0) {
+            delete key;
+            isc_throw(BadKey, "not a RSA Private Key");
+        }
+        priv_.reset(dynamic_cast<Botan::RSA_PrivateKey*>(key));
+        if (!priv_) {
+            delete key;
+            isc_throw(LibraryError, "dynamic_cast");
+        }
+    } else if ((kind_ == PRIVATE) && (key_format == DNS)) {
+        // bind9 .private file
+        // warn when password not empty
+        if ((hash_ != MD5) && (hash_ != SHA1) &&
+            (hash_ != SHA256) && (hash_ != SHA512)) {
+            isc_throw(UnsupportedAlgorithm,
+                      "Not compatible hash algorithm: " <<
+                      static_cast<int>(hash_));
+        }
+        std::ifstream fp(filename.c_str(), std::ios::in);
+        if (!fp.is_open()) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        bool got_algorithm = false;
+        bool got_modulus = false;
+        bool got_pub_exponent = false;
+        bool got_priv_exponent = false;
+        bool got_prime1 = false;
+        bool got_prime2 = false;
+        Botan::BigInt n;
+        Botan::BigInt e;
+        Botan::BigInt d;
+        Botan::BigInt p;
+        Botan::BigInt q;
+        while (fp.good()) {
+            std::string line;
+            getline(fp, line);
+            if (line.find("Algorithm:") == 0) {
+                if (got_algorithm) {
+                    fp.close();
+                    isc_throw(BadKey, "Two Algorithm entries");
+                }
+                got_algorithm = true;
+                std::string value = line.substr(strlen("Algorithm:") + 1,
+                                                std::string::npos);
+                int alg = std::atoi(value.c_str());
+                if (alg == 1) {
+                    // RSAMD5
+                    if (hash_ != MD5) {
+                        fp.close();
+                        isc_throw(BadKey, "Require a RSA MD5 key");
+                    }
+                } else if ((alg == 5) || (alg == 7)) {
+                    // RSASHA1 or RSASHA1-NSEC3-SHA1
+                    if (hash_ != SHA1) {
+                        fp.close();
+                        isc_throw(BadKey, "Require a RSA SHA1 key");
+                    }
+                } else if (alg == 8) {
+                    // RSASHA256
+                    if (hash_ != SHA256) {
+                        fp.close();
+                        isc_throw(BadKey, "Require a RSA SHA256 key");
+                    }
+                } else if (alg == 10) {
+                    // RSASHA512
+                    if (hash_ != SHA512) {
+                        fp.close();
+                        isc_throw(BadKey, "Require a RSA SHA512 key");
+                    }
+                } else {
+                    fp.close();
+                    isc_throw(BadKey, "Bad Algorithm: " << alg);
+                }
+            } else if (line.find("Modulus:") == 0) {
+                if (got_modulus) {
+                    fp.close();
+                    isc_throw(BadKey, "Two Modulus entries");
+                }
+                got_modulus = true;
+                std::string value = line.substr(strlen("Modulus:") + 1,
+                                                std::string::npos);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    fp.close();
+                    isc_throw(BadKey, "Modulus: " << exc.what());
+                }
+                n = Botan::BigInt(&bin[0], bin.size());
+          } else if (line.find("PublicExponent:") == 0) {
+                if (got_pub_exponent) {
+                    fp.close();
+                    isc_throw(BadKey, "Two PublicExponent entries");
+                }
+                got_pub_exponent = true;
+                std::string value =
+                    line.substr(strlen("PublicExponent:") + 1,
+                                std::string::npos);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    fp.close();
+                    isc_throw(BadKey, "PublicExponent: " << exc.what());
+                }
+                e = Botan::BigInt(&bin[0], bin.size());
+            } else if (line.find("PrivateExponent:") == 0) {
+                if (got_priv_exponent) {
+                    fp.close();
+                    isc_throw(BadKey, "Two PrivateExponent entries");
+                }
+                got_priv_exponent = true;
+                std::string value =
+                    line.substr(strlen("PrivateExponent:") + 1,
+                                std::string::npos);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    fp.close();
+                    isc_throw(BadKey, "PrivateExponent: " << exc.what());
+                }
+                d = Botan::BigInt(&bin[0], bin.size());
+            } else if (line.find("Prime1:") == 0) {
+                if (got_prime1) {
+                    fp.close();
+                    isc_throw(BadKey, "Two Prime1 entries");
+                }
+                got_prime1 = true;
+                std::string value = line.substr(strlen("Prime1:") + 1,
+                                                std::string::npos);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    fp.close();
+                    isc_throw(BadKey, "Prime1: " << exc.what());
+                }
+                p = Botan::BigInt(&bin[0], bin.size());
+            } else if (line.find("Prime2:") == 0) {
+                if (got_prime2) {
+                    fp.close();
+                    isc_throw(BadKey, "Two Prime2 entries");
+                }
+                got_prime2 = true;
+                std::string value = line.substr(strlen("Prime2:") + 1,
+                                                std::string::npos);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    fp.close();
+                    isc_throw(BadKey, "Prime2: " << exc.what());
+                }
+                q = Botan::BigInt(&bin[0], bin.size());
+            }
+        }
+        fp.close();
+        if (!got_algorithm) {
+            isc_throw(BadKey, "Missing Algorithm entry");
+        }
+        if (!got_modulus) {
+            isc_throw(BadKey, "Missing Modulus entry");
+        }
+        if (!got_pub_exponent) {
+            isc_throw(BadKey, "Missing PublicExponent entry");
+        }
+        if (!got_priv_exponent) {
+            isc_throw(BadKey, "Missing PrivateExponent entry");
+        }
+        if (!got_prime1) {
+            isc_throw(BadKey, "Missing Prime1 entry");
+        }
+        if (!got_prime2) {
+            isc_throw(BadKey, "Missing Prime2 entry");
+        }
+        Botan::AutoSeeded_RNG rng;
+        try {
+            priv_.reset(new Botan::RSA_PrivateKey(rng, p, q, e, d, n));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "RSA_PrivateKey" << exc.what());
+        }
+    } else if (kind_ == PRIVATE) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Private Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((kind_ == PUBLIC) && (key_format == ASN1)) {
+        // SubjectPublicKeyInfo PEM file
+        // warn when password not empty
+        Botan::Public_Key* key;
+        try {
+            key = Botan::X509::load_key(filename);
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "X509::load_key: " << exc.what());
+        }
+        if (key->algo_name().compare("RSA") != 0) {
+            delete key;
+            isc_throw(BadKey, "not a RSA Public Key");
+        }
+        pub_.reset(dynamic_cast<Botan::RSA_PublicKey*>(key));
+        if (!pub_) {
+            delete key;
+            isc_throw(LibraryError, "dynamic_cast");
+        }
+    } else if ((kind_ == PUBLIC) && (key_format == DNS)) {
+        // bind9 .key file (RDATA)
+        // warn when password not empty
+        if ((hash_ != MD5) && (hash_ != SHA1) &&
+            (hash_ != SHA256) && (hash_ != SHA512)) {
+            isc_throw(UnsupportedAlgorithm,
+                      "Not compatible hash algorithm: " <<
+                      static_cast<int>(hash_));
+        }
+        std::ifstream fp(filename.c_str(), std::ios::in);
+        if (!fp.is_open()) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        std::string line;
+        bool found = false;
+        while (fp.good()) {
+            getline(fp, line);
+            if (line.empty() || (line[0] == ';')) {
+                continue;
+            }
+            if (line.find("DNSKEY") == std::string::npos) {
+                continue;
+            }
+            found = true;
+            if (line[line.size() - 1] == '\n') {
+                line.erase(line.size() - 1);
+            }
+            break;
+        }
+        fp.close();
+        if (!found) {
+            isc_throw(BadKey, "Can't find a DNSKEY");
+        }
+        const std::string b64 =
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
+            "ghijklmnopqrstuvwxyz0123456789+/=";
+        const std::string value = line.substr(line.find_last_not_of(b64));
+        std::vector<uint8_t> bin;
+        try {
+            util::encode::decodeBase64(value, bin);
+        } catch (const BadValue& exc) {
+           isc_throw(BadKey, "Can't decode base64: " << exc.what());
+        }
+        size_t key_len = bin.size();
+        const uint8_t* p = &bin[0];
+        size_t e_bytes = *p++;
+        --key_len;
+        if (e_bytes == 0) {
+            if (key_len < 2) {
+                isc_throw(BadKey,
+                          "Bad RSA Public Key: short exponent length");
+            }
+            e_bytes = (*p++) << 8;
+            e_bytes += *p++;
+            key_len -= 2;
+        }
+        if (key_len < e_bytes) {
+            isc_throw(BadKey, "Bad RSA Public Key: short exponent");
+        }
+        if ((key_len - e_bytes) < 64) {
+            isc_throw(BadKey, "Bad RSA Public Key: too short: " <<
+                      (key_len - e_bytes) * 8);
+        }
+        if ((key_len - e_bytes) > 512) {
+            isc_throw(BadKey, "Bad RSA Public Key: too large: " <<
+                      (key_len - e_bytes) * 8);
+        }
+        Botan::BigInt e(p, e_bytes);
+        p += e_bytes;
+        key_len -= e_bytes;
+        Botan::BigInt n(p, key_len);
+        try {
+            pub_.reset(new Botan::RSA_PublicKey(n, e));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "RSA_PublicKey: " << exc.what());
+        }
+    } else if (kind_ == PUBLIC) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Public Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((kind_ == CERT) && (key_format == ASN1)) {
+        // X.509 Public Key Certificate PEM file
+        // warn when password not empty
+        try {
+            x509_.reset(new Botan::X509_Certificate(filename));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "X509_Certificate: " << exc.what());
+        }
+        const Botan::AlgorithmIdentifier
+            sig_algo(x509_->signature_algorithm());
+        if (hash_ == MD5) {
+            const Botan::AlgorithmIdentifier
+                rsa_md5("1.2.840.113549.1.1.4",
+                        Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+            if (sig_algo != rsa_md5) {
+                x509_.reset();
+                isc_throw(BadKey, "Require a RSA MD5 certificate");
+            }
+        } else if (hash_ == SHA1) {
+            const Botan::AlgorithmIdentifier
+                rsa_sha1("1.2.840.113549.1.1.5",
+                         Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+            if (sig_algo != rsa_sha1) {
+                x509_.reset();
+                isc_throw(BadKey, "Require a RSA SHA1 certificate");
+            }
+        } else if (hash_ == SHA224) {
+            const Botan::AlgorithmIdentifier
+                rsa_sha224("1.2.840.113549.1.1.14",
+                           Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+            if (sig_algo != rsa_sha224) {
+                x509_.reset();
+                isc_throw(BadKey, "Require a RSA SHA224 certificate");
+            }
+        } else if (hash_ == SHA256) {
+            const Botan::AlgorithmIdentifier
+                rsa_sha256("1.2.840.113549.1.1.11",
+                           Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+            if (sig_algo != rsa_sha256) {
+                x509_.reset();
+                isc_throw(BadKey, "Require a RSA SHA256 certificate");
+            }
+        } else if (hash_ == SHA384) {
+            const Botan::AlgorithmIdentifier
+                rsa_sha384("1.2.840.113549.1.1.12",
+                           Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+            if (sig_algo != rsa_sha384) {
+                x509_.reset();
+                isc_throw(BadKey, "Require a RSA SHA384 certificate");
+            }
+        } else if (hash_ == SHA512) {
+            const Botan::AlgorithmIdentifier
+                rsa_sha512("1.2.840.113549.1.1.13",
+                           Botan::AlgorithmIdentifier::USE_NULL_PARAM);
+            if (sig_algo != rsa_sha512) {
+                x509_.reset();
+                isc_throw(BadKey, "Require a RSA SHA512 certificate");
+            }
+        } else {
+            x509_.reset();
+            isc_throw(UnsupportedAlgorithm,
+                      "Bad hash algorithm for certificate: " <<
+                      static_cast<int>(hash_));
+        }
+        Botan::Public_Key* key;
+        try {
+            key = x509_->subject_public_key();
+        } catch (const std::exception& exc) {
+            x509_.reset();
+            isc_throw(BadKey, "subject_public_key: " << exc.what());
+        }
+        if (key->algo_name().compare("RSA") != 0) {
+            delete key;
+            x509_.reset();
+            isc_throw(BadKey, "not a RSA Public Key");
+        }
+        pub_.reset(dynamic_cast<Botan::RSA_PublicKey*>(key));
+        if (!pub_) {
+            delete key;
+            x509_.reset();
+            isc_throw(LibraryError, "dynamic_cast");
+        }
+    } else if (kind_ == CERT) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown Public Key Certificate format: " <<
+                  static_cast<int>(key_format));
+    } else {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Key kind: " << static_cast<int>(kind_));
+    }
+
+    if (kind_ == PRIVATE) {
+        try {
+            if (!pub_) {
+                pub_.reset(new Botan::RSA_PublicKey(priv_->get_n(),
+                                                    priv_->get_e()));
+            }
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "priv to pub: " << exc.what());
+        }
+        try {
+            signer_.reset(new Botan::PK_Signer(*priv_, emsa));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "PK_Signer: " << exc.what());
+        }
+    } else {
+        try {
+            verifier_.reset(new Botan::PK_Verifier(*pub_, emsa));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "PK_Verifier: " << exc.what());
+        }
+    }
+}
+
+/// @brief Destructor
+RsaAsymImpl::~RsaAsymImpl() { }
+
+/// @brief Returns the AsymAlgorithm of the object
+AsymAlgorithm RsaAsymImpl::getAsymAlgorithm() const {
+    return (algo_);
+}
+
+/// @brief Returns the HashAlgorithm of the object
+HashAlgorithm RsaAsymImpl::getHashAlgorithm() const {
+    return (hash_);
+}
+
+/// @brief Returns the AsymKeyKind of the object
+AsymKeyKind RsaAsymImpl::getAsymKeyKind() const {
+    return (kind_);
+}
+
+/// @brief Returns the key size in bits
+size_t RsaAsymImpl::getKeySize() const {
+    if (kind_ == PRIVATE) {
+        return (priv_->get_n().bits());
+    } else {
+        return (pub_->get_n().bits());
+    }
+}
+
+/// @brief Returns the output size of the signature
+size_t RsaAsymImpl::getSignatureLength(const AsymFormat sig_format) const {
+    switch (sig_format) {
+    case BASIC:
+    case ASN1:
+    case DNS:
+        // In all cases a big integer of the size of n
+        if (kind_ == PRIVATE) {
+            return (priv_->get_n().bytes());
+        } else {
+            return (pub_->get_n().bytes());
+        }
+    default:
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Signature format: " <<
+                  static_cast<int>(sig_format));
+    }
+}           
+
+/// @brief Add data to digest
+void RsaAsymImpl::update(const void* data, const size_t len) {
+    try {
+        if (kind_ == PRIVATE) {
+            signer_->update(reinterpret_cast<const Botan::byte*>(data), len);
+        } else {
+            verifier_->update(reinterpret_cast<const Botan::byte*>(data), len);
+        }            
+    } catch (const std::exception& exc) {
+        isc_throw(LibraryError, "update: " << exc.what());
+    }
+}
+
+/// @brief Calculate the final signature
+void RsaAsymImpl::sign(isc::util::OutputBuffer& result, size_t len,
+          const AsymFormat) {
+    try {
+        Botan::SecureVector<Botan::byte> b_result;
+        Botan::AutoSeeded_RNG rng;
+        b_result = signer_->signature(rng);
+        if (len > b_result.size()) {
+            len = b_result.size();
+        }
+        result.writeData(b_result.begin(), len);
+    } catch (const std::exception& exc) {
+        isc_throw(LibraryError, "signature: " << exc.what());
+    }
+}
+
+/// @brief Calculate the final signature
+void RsaAsymImpl::sign(void* result, size_t len, const AsymFormat sig_format) {
+    try {
+        Botan::SecureVector<Botan::byte> b_result;
+        Botan::AutoSeeded_RNG rng;
+        b_result = signer_->signature(rng);
+        size_t output_size = getSignatureLength(sig_format);
+        if (output_size > len) {
+            output_size = len;
+        }
+        std::memcpy(result, b_result.begin(), output_size);
+    } catch (const std::exception& exc) {
+        isc_throw(LibraryError, "signature: " << exc.what());
+    }
+}
+
+/// @brief Calculate the final signature
+std::vector<uint8_t> RsaAsymImpl::sign(size_t len, const AsymFormat) {
+    try {
+        Botan::SecureVector<Botan::byte> b_result;
+        Botan::AutoSeeded_RNG rng;
+        b_result = signer_->signature(rng);
+        if (len > b_result.size()) {
+            return (std::vector<uint8_t>(b_result.begin(), b_result.end()));
+        } else {
+            return (std::vector<uint8_t>(b_result.begin(), &b_result[len]));
+        }
+    } catch (const std::exception& exc) {
+        isc_throw(LibraryError, "signature: " << exc.what());
+    }
+}
+
+/// @brief Verify an existing signature
+bool RsaAsymImpl::verify(const void* sig, size_t len,
+                         const AsymFormat sig_format) {
+    size_t size = getSignatureLength(sig_format);
+    if (len != size) {
+        return false;
+    }
+    const Botan::byte* sigbuf = reinterpret_cast<const Botan::byte*>(sig);
+    try {
+        return verifier_->check_signature(sigbuf, len);
+    } catch (const std::exception& exc) {
+        isc_throw(LibraryError, "check_signature: " << exc.what());
+    }
+}
+
+/// \brief Clear the crypto state and go back to the initial state
+void RsaAsymImpl::clear() {
+    std::string hash = btn::getHashAlgorithmName(hash_);
+    if (hash.compare("Unknown") == 0) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown hash algorithm: " << static_cast<int>(hash_));
+    }
+    std::string emsa = "EMSA3(" + hash + ")";
+    if (kind_ == PRIVATE) {
+        try {
+            signer_.reset(new Botan::PK_Signer(*priv_, emsa));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "PK_Signer: " << exc.what());
+        }
+    } else {
+        try {
+            verifier_.reset(new Botan::PK_Verifier(*pub_, emsa));
+        } catch (const std::exception& exc) {
+            isc_throw(BadKey, "PK_Verifier: " << exc.what());
+        }
+    }
+}
+
+/// @brief Export the key value (binary)
+std::vector<uint8_t>
+    RsaAsymImpl::exportkey(const AsymKeyKind key_kind,
+                           const AsymFormat key_format) const {
+    if ((key_kind == PRIVATE) && (key_format == BASIC)) {
+        // PKCS#1 Private Key
+        if (kind_ != PRIVATE) {
+            isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
+        }
+        Botan::MemoryVector<Botan::byte> der;
+        try {
+            der = priv_->pkcs8_private_key();
+        } catch (const std::exception& exc) {
+            isc_throw(LibraryError, "pkcs8_private_key: " << exc.what());
+        }
+        return std::vector<uint8_t>(der.begin(), der.end());
+    } else if (key_kind == PRIVATE) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Private Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((key_kind == PUBLIC) && (key_format == BASIC)) {
+        // PKCS#1 Public Key
+        Botan::MemoryVector<Botan::byte> der;
+        try {
+            der = pub_->x509_subject_public_key();
+        } catch (const std::exception& exc) {
+            isc_throw(LibraryError,
+                      "x509_subject_public_key: " << exc.what());
+        }
+        return std::vector<uint8_t>(der.begin(), der.end());
+    } else if ((key_kind == PUBLIC) && (key_format == ASN1)) {
+        // SubjectPublicKeyInfo
+        Botan::MemoryVector<Botan::byte> ber;
+        try {
+            ber = Botan::X509::BER_encode(*pub_);
+        } catch (const std::exception& exc) {
+            isc_throw(LibraryError, "X509::BER_encode: " << exc.what());
+        }
+        return std::vector<uint8_t>(ber.begin(), ber.end());
+    } else if ((key_kind == PUBLIC) && (key_format == DNS)) {
+        // RFC 3110 DNS wire format
+        size_t e_bytes = pub_->get_e().bytes();
+        size_t mod_bytes = pub_->get_n().bytes();
+        size_t x_bytes = 1;
+        if (e_bytes >= 256) {
+            x_bytes += 2;
+        }
+        std::vector<uint8_t> rdata(x_bytes + e_bytes + mod_bytes);
+        if (e_bytes < 256) {
+            rdata[0] = e_bytes;
+        } else {
+            rdata[0] = 0;
+            rdata[1] = (e_bytes >> 8) & 0xff;
+            rdata[2] = e_bytes & 0xff;
+        }
+        pub_->get_e().binary_encode(&rdata[x_bytes]);
+        pub_->get_n().binary_encode(&rdata[x_bytes + e_bytes]);
+        return rdata;
+    } else if (key_kind == PUBLIC) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Public Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((key_kind == CERT) && (key_format == ASN1)) {
+        // X.509 Public Key Certificate
+        if (kind_ != CERT) {
+            isc_throw(UnsupportedAlgorithm, "Have no Certificate");
+        }
+        Botan::MemoryVector<Botan::byte> ber;
+        try {
+            ber = x509_->BER_encode();
+        } catch (const std::exception& exc) {
+            isc_throw(LibraryError, "BER_encode" << exc.what());
+        }
+        return std::vector<uint8_t>(ber.begin(), ber.end());
+    } else if (key_kind == CERT) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown Certificate format: " <<
+                  static_cast<int>(key_format));
+    } else {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Key kind: " << static_cast<int>(key_kind));
+    }
+}
+
+/// @brief Export the key value (file)
+void RsaAsymImpl::exportkey(const std::string& filename,
+                            const std::string& password,
+                            const AsymKeyKind key_kind,
+                            const AsymFormat key_format) const {
+    if ((key_kind == PRIVATE) && (key_format == ASN1)) {
+        // PKCS#8 Private Key PEM file
+        std::string pem;
+        Botan::AutoSeeded_RNG rng;
+        try {
+            pem = Botan::PKCS8::PEM_encode(*priv_, rng,
+                                           password, "AES-128/CBC");
+        } catch (const std::exception& exc) {
+            isc_throw(LibraryError, "PKCS8::PEM_encode: " << exc.what());
+        }
+        std::ofstream fp(filename.c_str(),
+                         std::ofstream::out | std::ofstream::trunc);
+        if (fp.is_open()) {
+            fp.write(pem.c_str(), pem.size());
+            fp.close();
+        } else {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+    } else if ((key_kind == PRIVATE) && (key_format == DNS)) {
+        //  bind9 .private file
+        if (kind_ != PRIVATE) {
+            isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
+        }
+        if ((hash_ != MD5) && (hash_ != SHA1) &&
+            (hash_ != SHA256) && (hash_ != SHA512)) {
+            isc_throw(UnsupportedAlgorithm,
+                      "Not compatible hash algorithm: " <<
+                      static_cast<int>(hash_));
+        }
+        std::ofstream fp(filename.c_str(),
+                         std::ofstream::out | std::ofstream::trunc);
+        if (!fp.is_open()) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        fp << "Private-key-format: v1.2\n";
+        if (hash_ == MD5) {
+            fp << "Algorithm: 1 (RSA)\n";
+        } else if (hash_ == SHA1) {
+            fp << "Algorithm: 5 (RSASHA1)\n";
+        } else if (hash_ == SHA256) {
+            fp << "Algorithm: 8 (RSASHA256)\n";
+        } else if (hash_ == SHA512) {
+            fp << "Algorithm: 10 (RSASHA512)\n";
+        }
+        std::vector<uint8_t> bin;
+        bin.resize(priv_->get_n().bytes());
+        priv_->get_n().binary_encode(&bin[0]);
+        fp << "Modulus: " << util::encode::encodeBase64(bin) << '\n';
+        bin.resize(priv_->get_e().bytes());
+        priv_->get_e().binary_encode(&bin[0]);
+        fp << "PublicExponent: " <<
+            util::encode::encodeBase64(bin) << '\n';
+        bin.resize(priv_->get_d().bytes());
+        priv_->get_d().binary_encode(&bin[0]);
+        fp << "PrivateExponent: " <<
+            util::encode::encodeBase64(bin) << '\n';
+        bin.resize(priv_->get_p().bytes());
+        priv_->get_p().binary_encode(&bin[0]);
+        fp << "Prime1: " << util::encode::encodeBase64(bin) << '\n';
+        bin.resize(priv_->get_q().bytes());
+        priv_->get_q().binary_encode(&bin[0]);
+        fp << "Prime2: " << util::encode::encodeBase64(bin) << '\n';
+        bin.resize(priv_->get_d1().bytes());
+        priv_->get_d1().binary_encode(&bin[0]);
+        fp << "Exponent1: " << util::encode::encodeBase64(bin) << '\n';
+        bin.resize(priv_->get_d2().bytes());
+        priv_->get_d2().binary_encode(&bin[0]);
+        fp << "Exponent2: " << util::encode::encodeBase64(bin) << '\n';
+        bin.resize(priv_->get_c().bytes());
+        priv_->get_c().binary_encode(&bin[0]);
+        fp << "Coefficient: " << util::encode::encodeBase64(bin) << '\n';
+        fp.close();
+    } else if (key_kind == PRIVATE) {
+        if (kind_ != PRIVATE) {
+            isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
+        }
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Private Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((key_kind == PUBLIC) && (key_format == ASN1)) {
+        // SubjectPublicKeyInfo PEM file
+        // warn when password not empty
+        std::string pem;
+        try {
+            pem = Botan::X509::PEM_encode(*pub_);
+        } catch (const std::exception& exc) {
+            isc_throw(LibraryError, "X509::PEM_encode: " << exc.what());
+        }
+        std::ofstream fp(filename.c_str(),
+                         std::ofstream::out | std::ofstream::trunc);
+        if (fp.is_open()) {
+            fp.write(pem.c_str(), pem.size());
+            fp.close();
+        } else {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+    }  else if ((key_kind == PUBLIC) && (key_format == DNS)) {
+        // bind9 .key file (RDATA)
+        // warn when password not empty
+        std::vector<uint8_t> bin = exportkey(key_kind, key_format);
+        std::ofstream fp(filename.c_str(),
+                         std::ofstream::out | std::ofstream::trunc);
+        if (!fp.is_open()) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        fp << "; DNSKEY RDATA: " << util::encode::encodeBase64(bin) << '\n';
+        fp.close();
+    } else if (key_kind == PUBLIC) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Public Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((key_kind == CERT) && (key_format == ASN1)) {
+        // Public Key Certificate PEM file
+        // warn when password not empty
+        if (!x509_) {
+            isc_throw(UnsupportedAlgorithm, "Have no Certificate");
+        }
+        std::string pem;
+        try {
+            pem = x509_->PEM_encode();
+        } catch (const std::exception& exc) {
+            isc_throw(LibraryError, "PEM_encode: " << exc.what());
+        }
+        std::ofstream fp(filename.c_str(),
+                         std::ofstream::out | std::ofstream::trunc);
+        if (fp.is_open()) {
+            fp.write(pem.c_str(), pem.size());
+            fp.close();
+        } else {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+    } else if (key_kind == CERT) {
+        if (!x509_) {
+            isc_throw(UnsupportedAlgorithm, "Have no Certificate");
+        }
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown Certificate format: " <<
+                  static_cast<int>(key_format));
+    } else {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Key kind: " << static_cast<int>(key_kind));
+    }
+}
+
+/// @brief Check the validity
+bool RsaAsymImpl::validate() const {
+    Botan::AutoSeeded_RNG rng;
+    Botan::X509_Store store;
+    Botan::X509_Code status;
+    switch (kind_) {
+    case PUBLIC:
+        // what to do?
+        try {
+            return pub_->check_key(rng, true);
+        } catch (const std::exception& exc) {
+            isc_throw(LibraryError, "check_key: " << exc.what());
+        }
+    case PRIVATE:
+        try {
+            return priv_->check_key(rng, true);
+        } catch (const std::exception& exc) {
+            isc_throw(LibraryError, "check_key: " << exc.what());
+        }
+    case CERT:
+        store.add_cert(*x509_, true);
+        status = store.validate_cert(*x509_);
+        if (status == Botan::VERIFIED) {
+            return true;
+        }
+        return false;
+    default:
+        return false;
+    }
+}
+
+/// @brief Compare two keys
+bool RsaAsymImpl::compare(const RsaAsymImpl* other,
+                          const AsymKeyKind key_kind) const {
+    if (!other || (other->algo_ != RSA_)) {
+        return false;
+    }
+    Botan::BigInt e, n;
+    switch (key_kind) {
+    case CERT:
+        // Special case for cert - cert
+        if ((kind_ == CERT) && (other->kind_ == CERT)) {
+            return (*x509_ == *other->x509_);
+        }
+        // At least one should be a cert
+        if ((kind_ != CERT) && (other->kind_ != CERT)) {
+            return false;
+        }
+        // For all other cases just compare public keys
+        // Falls into
+    case PUBLIC:
+        if (kind_ == PRIVATE) {
+            e = priv_->get_e();
+            n = priv_->get_n();;
+        } else if ((kind_ == PUBLIC) || (kind_ == CERT)) {
+            e = pub_->get_e();
+            n = pub_->get_n();
+        } else {
+            return false;
+        }
+        if (other->kind_ == PRIVATE) {
+            return ((e == other->priv_->get_e()) &&
+                    (n == other->priv_->get_n()));
+        } else if ((other->kind_ == PUBLIC) || (other->kind_ == CERT)) {
+            return ((e == other->pub_->get_e()) &&
+                    (n == other->pub_->get_n()));
+        } else {
+            return false;
+        }
+    case PRIVATE:
+        if ((kind_ != PRIVATE) || (other->kind_ != PRIVATE)) {
+            return false;
+        }
+        // If public keys match so private too
+        return ((priv_->get_e() == other->priv_->get_e()) &&
+                (priv_->get_n() == other->priv_->get_n()));
+    default:
+        return false;
+    }
+}
+
+} // namespace cryptolink
+} // namespace isc
diff --git a/src/lib/cryptolink/botan_rsa.h b/src/lib/cryptolink/botan_rsa.h
new file mode 100644 (file)
index 0000000..6329946
--- /dev/null
@@ -0,0 +1,146 @@
+// Copyright (C) 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+namespace isc {
+namespace cryptolink {
+
+/// @brief Botan implementation of asymmetrical cryptography (Asym).          
+// Each method is the counterpart of the Asym corresponding method.
+class RsaAsymImpl : public AsymImpl {
+public:
+    /// @brief Constructor from a key, asym and hash algorithm,
+    ///        key kind and key binary format
+    ///
+    /// See constructor of the @ref isc::cryptolink::Asym class for details.
+    ///
+    /// @param key            The key to sign/verify with
+    /// @param len            The length of the key
+    /// @param hash_algorithm The hash algorithm
+    /// @param key_kind       The key kind
+    /// @param key_format     The key binary format
+    RsaAsymImpl(const void* key, size_t key_len,
+                const HashAlgorithm hash_algorithm,
+                const AsymKeyKind key_kind,
+                const AsymFormat key_format);
+
+    /// @brief Constructor from a key file with password,
+    ///        asym and hash algorithm, key kind and key binary format
+    ///
+    /// See constructor of the @ref isc::cryptolink::Asym class for details.
+    ///
+    /// @param filename       The key file name/path
+    /// @param password       The PKCS#8 password
+    /// @param hash_algorithm The hash algorithm
+    /// @param key_kind       The key kind
+    /// @param key_format     The key binary format
+    RsaAsymImpl(const std::string& filename,
+                const std::string& password,
+                const HashAlgorithm hash_algorithm,
+                const AsymKeyKind key_kind,
+                const AsymFormat key_format);
+
+    /// @brief Destructor
+    ~RsaAsymImpl();
+
+    /// @brief Returns the AsymAlgorithm of the object
+    AsymAlgorithm getAsymAlgorithm() const;
+
+    /// @brief Returns the HashAlgorithm of the object
+    HashAlgorithm getHashAlgorithm() const;
+
+    /// @brief Returns the AsymKeyKind of the object
+    AsymKeyKind getAsymKeyKind() const;
+
+    /// @brief Returns the key size in bits
+    size_t getKeySize() const;
+
+    /// @brief Returns the output size of the signature
+    ///
+    /// \param sig_format The signature binary format
+    size_t getSignatureLength(const AsymFormat sig_format) const;
+
+    /// @brief Add data to digest
+    ///
+    /// See @ref isc::cryptolink::AsymBase::update() for details.
+    void update(const void* data, const size_t len);
+
+    /// @brief Calculate the final signature
+    ///
+    /// See @ref isc::cryptolink::AsymBase::sign() for details.
+    void sign(isc::util::OutputBuffer& result, size_t len, const AsymFormat);
+
+    /// @brief Calculate the final signature
+    ///
+    /// See @ref isc::cryptolink::AsymBase::sign() for details.
+    void sign(void* result, size_t len, const AsymFormat sig_format);
+
+    /// @brief Calculate the final signature
+    ///
+    /// See @ref isc::cryptolink::AsymBase::sign() for details.
+    std::vector<uint8_t> sign(size_t len, const AsymFormat);
+
+    /// @brief Verify an existing signature
+    ///
+    /// See @ref isc::cryptolink::AsymBase::verify() for details.
+    bool verify(const void* sig, size_t len, const AsymFormat sig_format);
+
+    /// \brief Clear the crypto state and go back to the initial state
+    /// (must be called before reusing an Asym object)
+    void clear();
+
+    /// @brief Export the key value (binary)
+    ///
+    /// See @ref isc::cryptolink::AsymBase::exportkey() for details
+    std::vector<uint8_t> exportkey(const AsymKeyKind key_kind,
+                                   const AsymFormat key_format) const;
+
+    /// @brief Export the key value (file)
+    ///
+    /// See @ref isc::cryptolink::AsymBase::exportkey() for details
+    void exportkey(const std::string& filename,
+                   const std::string& password,
+                   const AsymKeyKind key_kind,
+                   const AsymFormat key_format) const;
+
+    /// @brief Check the validity
+    ///
+    /// See @ref isc::cryptolink::AsymBase::validate() for details
+    bool validate() const;
+
+    /// @brief Compare two keys
+    ///
+    /// See @ref isc::cryptolink::Asym::compare() for details
+    bool compare(const RsaAsymImpl* other, const AsymKeyKind key_kind) const;
+
+private:
+    /// @brief The asymmetrical cryptography algorithm
+    AsymAlgorithm algo_;
+    /// @brief The hash algorithm
+    HashAlgorithm hash_;
+    /// @brief The key kind
+    AsymKeyKind kind_;
+    /// @brief The protected pointer to the Botan private key
+    boost::scoped_ptr<Botan::RSA_PrivateKey> priv_;
+    /// @brief The protected pointer to the Botan public key
+    boost::scoped_ptr<Botan::RSA_PublicKey> pub_;
+    /// @brief The protected pointer to the Botan certificate
+    boost::scoped_ptr<Botan::X509_Certificate> x509_;
+    /// @brief The protected pointer to the Botan signer
+    boost::scoped_ptr<Botan::PK_Signer> signer_;
+    /// @brief The protected pointer to the Botan verifier
+    boost::scoped_ptr<Botan::PK_Verifier> verifier_;
+};
+
+} // namespace cryptolink
+} // namespace isc
index d2e0ccb3410ccb7d5fdcebbc1bc95109eb9a6b2a..1907fd5dc8ded402ea89c572cb41426aef45b759 100644 (file)
 #include <cryptolink.h>
 #include <cryptolink/crypto_asym.h>
 
-#include <boost/scoped_ptr.hpp>
-
 #include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <openssl/rsa.h>
-#include <openssl/x509.h>
 
-#include <util/encode/base64.h>
 #include <hooks/hooks_manager.h>
 #include <hooks/callout_handle.h>
 #include <cryptolink/openssl_common.h>
-
-#include <cstdio>
-#include <cstring>
+#include <cryptolink/openssl_rsa.h>
 
 namespace {
 
@@ -41,1412 +33,6 @@ int hook_point_validate_certificate =
 namespace isc {
 namespace cryptolink {
 
-/// @brief OpenSSL implementation of asymmetrical cryptography (Asym).
-// Each method is the counterpart of the Asym corresponding method.
-class RsaAsymImpl : public AsymImpl {
-public:
-    /// @brief Constructor from a key, asym and hash algorithm,
-    ///        key kind and key binary format
-    ///
-    /// See constructor of the @ref isc::cryptolink::Asym class for details.
-    ///
-    /// @param key            The key to sign/verify with
-    /// @param len            The length of the key
-    /// @param hash_algorithm The hash algorithm
-    /// @param key_kind       The key kind
-    /// @param key_format     The key binary format
-    RsaAsymImpl(const void* key, size_t key_len,
-                const HashAlgorithm hash_algorithm,
-                const AsymKeyKind key_kind,
-                const AsymFormat key_format) {
-        algo_ = RSA_;
-        hash_ = hash_algorithm;
-        kind_ = key_kind;
-        pkey_ = NULL;
-        x509_ = NULL;
-        const EVP_MD* md = ossl::getHashAlgorithm(hash_);
-        if (md == 0) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown hash algorithm: " <<
-                      static_cast<int>(hash_));
-        }
-        if (key_len == 0) {
-            isc_throw(BadKey, "Bad RSA " <<
-                      (kind_ != CERT ? "key" : "cert") <<
-                      " length: 0");
-        }
-
-        if ((kind_ == PRIVATE) && (key_format == BASIC)) {
-            // PKCS#1 Private Key
-            const unsigned char* p =
-                reinterpret_cast<const unsigned char*>(key);
-            RSA* rsa = d2i_RSAPrivateKey(NULL, &p,
-                                         static_cast<long>(key_len));
-            if (!rsa) {
-                isc_throw(BadKey, "d2i_RSAPrivateKey");
-            }
-            pkey_ = EVP_PKEY_new();
-            if (!pkey_) {
-                RSA_free(rsa);
-                throw std::bad_alloc();
-            }
-            if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
-                RSA_free(rsa);
-                EVP_PKEY_free(pkey_);
-                pkey_ = NULL;
-                isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
-            }
-            // set1 bumped the reference counter
-            RSA_free(rsa);
-        } else if (kind_ == PRIVATE) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Private Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((kind_ == PUBLIC) && (key_format == BASIC)) {
-            // PKCS#1 Public Key
-            const unsigned char* p =
-                reinterpret_cast<const unsigned char*>(key);
-            RSA* rsa = d2i_RSAPublicKey(NULL, &p,
-                                        static_cast<long>(key_len));
-            if (!rsa) {
-                isc_throw(BadKey, "d2i_RSAPublicKey");
-            }
-            pkey_ = EVP_PKEY_new();
-            if (!pkey_) {
-                RSA_free(rsa);
-                throw std::bad_alloc();
-            }
-            if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
-                RSA_free(rsa);
-                EVP_PKEY_free(pkey_);
-                pkey_ = NULL;
-                isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
-            }
-            // set1 bumped the reference counter
-            RSA_free(rsa);
-        } else if ((kind_ == PUBLIC) && (key_format == ASN1)) {
-            // SubjectPublicKeyInfo
-            const unsigned char* p =
-              reinterpret_cast<const unsigned char*>(key);
-            RSA* rsa = d2i_RSA_PUBKEY(NULL, &p, static_cast<long>(key_len));
-            if (!rsa) {
-                isc_throw(BadKey, "d2i_RSA_PUBKEY");
-            }
-            pkey_ = EVP_PKEY_new();
-            if (!pkey_) {
-                RSA_free(rsa);
-                throw std::bad_alloc();
-            }
-            if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
-                RSA_free(rsa);
-                EVP_PKEY_free(pkey_);
-                pkey_ = NULL;
-                isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
-            }
-            // set1 bumped the reference counter
-            RSA_free(rsa);
-        } else if ((kind_ == PUBLIC) && (key_format == DNS)) {
-            // RFC 3110 DNS wire format
-            // key_len == 0 was already checked
-            const uint8_t* p =
-                reinterpret_cast<const uint8_t*>(key);
-            unsigned int e_bytes = *p++;
-            --key_len;
-            if (e_bytes == 0) {
-                if (key_len < 2) {
-                    isc_throw(BadKey,
-                              "Bad RSA Public Key: short exponent length");
-                }
-                e_bytes = (*p++) << 8;
-                e_bytes += *p++;
-                key_len -= 2;
-            }
-            if (key_len < e_bytes) {
-                isc_throw(BadKey, "Bad RSA Public Key: short exponent");
-            }
-            if ((key_len - e_bytes) < 64) {
-                isc_throw(BadKey, "Bad RSA Public Key: too short: " <<
-                          (key_len - e_bytes) * 8);
-            }
-            if ((key_len - e_bytes) > 512) {
-                isc_throw(BadKey, "Bad RSA Public Key: too large: " <<
-                          (key_len - e_bytes) * 8);
-            }
-            RSA* rsa = RSA_new();
-            if (!rsa) {
-                throw std::bad_alloc();
-            }
-            rsa->e = BN_bin2bn(p, e_bytes, NULL);
-            p += e_bytes;
-            key_len -= e_bytes;
-            rsa->n = BN_bin2bn(p, key_len, NULL);
-            if (!rsa->e || !rsa->n) {
-                RSA_free(rsa);
-                throw std::bad_alloc();
-            }
-            pkey_ = EVP_PKEY_new();
-            if (!pkey_) {
-                RSA_free(rsa);
-                throw std::bad_alloc();
-            }
-            if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
-                RSA_free(rsa);
-                EVP_PKEY_free(pkey_);
-                pkey_ = NULL;
-                isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
-            }
-            // set1 bumped the reference counter
-            RSA_free(rsa);
-        } else if (kind_ == PUBLIC) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Public Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((kind_ == CERT) && (key_format == ASN1)) {
-            // X.509 Public Key Certificate
-            const unsigned char* p =
-                reinterpret_cast<const unsigned char*>(key);
-            x509_ = d2i_X509(NULL, &p, static_cast<long>(key_len));
-            if (!x509_) {
-                isc_throw(BadKey, "d2i_X509");
-            }
-            int sig_nid = OBJ_obj2nid(x509_->sig_alg->algorithm);
-            if (hash_ == MD5) {
-                if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.4")) {
-                    X509_free(x509_);
-                    x509_ = NULL;
-                    isc_throw(BadKey, "Require a RSA MD5 certificate");
-                }
-            } else if (hash_ == SHA1) {
-                if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.5")) {
-                    X509_free(x509_);
-                    x509_ = NULL;
-                    isc_throw(BadKey, "Require a RSA SHA1 certificate");
-                }
-            } else if (hash_ == SHA224) {
-                if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.14")) {
-                    X509_free(x509_);
-                    x509_ = NULL;
-                    isc_throw(BadKey, "Require a RSA SHA224 certificate");
-                }
-            } else if (hash_ == SHA256) {
-                if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.11")) {
-                    X509_free(x509_);
-                    x509_ = NULL;
-                    isc_throw(BadKey, "Require a RSA SHA256 certificate");
-                }
-            } else if (hash_ == SHA384) {
-                if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.12")) {
-                    X509_free(x509_);
-                    x509_ = NULL;
-                    isc_throw(BadKey, "Require a RSA SHA384 certificate");
-                }
-            } else if (hash_ == SHA512) {
-                if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.13")) {
-                    X509_free(x509_);
-                    x509_ = NULL;
-                    isc_throw(BadKey, "Require a RSA SHA512 certificate");
-                }
-            } else {
-                X509_free(x509_);
-                x509_ = NULL;
-                isc_throw(UnsupportedAlgorithm,
-                          "Bad hash algorithm for certificate: " <<
-                          static_cast<int>(hash_));
-            }
-            pkey_ = X509_get_pubkey(x509_);
-            if (!pkey_) {
-                X509_free(x509_);
-                x509_ = NULL;
-                isc_throw(BadKey, "X509_get_pubkey");
-            }
-            if (pkey_->type != EVP_PKEY_RSA) {
-                EVP_PKEY_free(pkey_);
-                pkey_ = NULL;
-                X509_free(x509_);
-                x509_ = NULL;
-                isc_throw(BadKey, "not a RSA Public Key");
-            }
-        } else if (kind_ == CERT) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown Certificate format: " <<
-                      static_cast<int>(key_format));
-        } else {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Key kind: " <<
-                      static_cast<int>(kind_));
-        }
-
-        mdctx_.reset(new EVP_MD_CTX);
-        EVP_MD_CTX_init(mdctx_.get());
-
-        if (!EVP_DigestInit_ex(mdctx_.get(), md, NULL)) {
-            EVP_MD_CTX_cleanup(mdctx_.get());
-            EVP_PKEY_free(pkey_);
-            pkey_ =NULL;
-            isc_throw(LibraryError, "EVP_DigestInit_ex");
-        }
-    }
-
-    /// @brief Constructor from a key file with password,
-    ///        asym and hash algorithm, key kind and key binary format
-    ///
-    /// See constructor of the @ref isc::cryptolink::Asym class for details.
-    ///
-    /// @param filename       The key file name/path
-    /// @param password       The PKCS#8 password
-    /// @param hash_algorithm The hash algorithm
-    /// @param key_kind       The key kind
-    /// @param key_format     The key binary format
-    RsaAsymImpl(const std::string& filename,
-                const std::string& password,
-                const HashAlgorithm hash_algorithm,
-                const AsymKeyKind key_kind,
-                const AsymFormat key_format) {
-        algo_ = RSA_;
-        hash_ = hash_algorithm;
-        kind_ = key_kind;
-        pkey_ = NULL;
-        x509_ = NULL;
-        const EVP_MD* md = ossl::getHashAlgorithm(hash_);
-        if (md == 0) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown hash algorithm: " <<
-                      static_cast<int>(hash_));
-        }
-
-        if ((kind_ == PRIVATE) &&
-            ((key_format == BASIC) || (key_format == ASN1))) {
-            // PKCS#1 or PKCS#8 Private Key PEM file
-            FILE* fp = fopen(filename.c_str(), "r");
-            if (!fp) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            char* pwd = NULL;
-            if (!password.empty()) {
-                pwd = const_cast<char*>(password.c_str());
-            }
-            pkey_ = PEM_read_PrivateKey(fp, NULL, 0, pwd);
-            fclose(fp);
-            if (!pkey_) {
-                isc_throw(BadKey, "PEM_read_PrivateKey");
-            }
-            if (pkey_->type != EVP_PKEY_RSA) {
-                EVP_PKEY_free(pkey_);
-                pkey_ = NULL;
-                isc_throw(BadKey, "not a RSA Private Key");
-            }
-        } else if ((kind_ == PRIVATE) && (key_format == DNS)) {
-            // bind9 .private file
-            // warn when password not empty
-            if ((hash_ != MD5) && (hash_ != SHA1) &&
-                (hash_ != SHA256) && (hash_ != SHA512)) {
-                isc_throw(UnsupportedAlgorithm,
-                          "Not compatible hash algorithm: " <<
-                          static_cast<int>(hash_));
-            }
-            FILE* fp = fopen(filename.c_str(), "r");
-            if (!fp) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            bool got_algorithm = false;
-            bool got_modulus = false;
-            bool got_pub_exponent = false;
-            bool got_priv_exponent = false;
-            bool got_prime1 = false;
-            bool got_prime2 = false;
-            bool got_exponent1 = false;
-            bool got_exponent2 = false;
-            bool got_coefficient = false;
-            RSA* rsa = RSA_new();
-            char line[4096];
-            while (fgets(line, sizeof(line), fp)) {
-                if (strncmp(line, "Algorithm:", strlen("Algorithm:")) == 0) {
-                    if (got_algorithm) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Two Algorithm entries");
-                    }
-                    got_algorithm = true;
-                    std::string value(line + strlen("Algorithm:") + 1);
-                    int alg = std::atoi(value.c_str());
-                    if (alg == 1) {
-                        // RSAMD5
-                        if (hash_ != MD5) {
-                            RSA_free(rsa);
-                            fclose(fp);
-                            isc_throw(BadKey, "Require a RSA MD5 key");
-                        }
-                    } else if ((alg == 5) || (alg == 7)) {
-                        // RSASHA1 or RSASHA1-NSEC3-SHA1
-                        if (hash_ != SHA1) {
-                            RSA_free(rsa);
-                            fclose(fp);
-                            isc_throw(BadKey, "Require a RSA SHA1 key");
-                        }
-                    } else if (alg == 8) {
-                        // RSASHA256
-                        if (hash_ != SHA256) {
-                            RSA_free(rsa);
-                            fclose(fp);
-                            isc_throw(BadKey, "Require a RSA SHA256 key");
-                        }
-                    } else if (alg == 10) {
-                        // RSASHA512
-                        if (hash_ != SHA512) {
-                            RSA_free(rsa);
-                            fclose(fp);
-                            isc_throw(BadKey, "Require a RSA SHA512 key");
-                        }
-                    } else {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Bad Algorithm: " << alg);
-                    }
-                } else if (strncmp(line, "Modulus:",
-                                   strlen("Modulus:")) == 0) {
-                    if (got_modulus) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Two Modulus entries");
-                    }
-                    got_modulus = true;
-                    std::string value(line + strlen("Modulus:") + 1);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Modulus: " << exc.what());
-                    }
-                    int len = static_cast<int>(bin.size());
-                    rsa->n = BN_bin2bn(&bin[0], len, NULL);
-              } else if (strncmp(line, "PublicExponent:",
-                                 strlen("PublicExponent:")) == 0) {
-                    if (got_pub_exponent) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Two PublicExponent entries");
-                    }
-                    got_pub_exponent = true;
-                    std::string value(line + strlen("PublicExponent:") + 1);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "PublicExponent: " << exc.what());
-                    }
-                    int len = static_cast<int>(bin.size());
-                    rsa->e = BN_bin2bn(&bin[0], len, NULL);
-                } else if (strncmp(line, "PrivateExponent:",
-                                   strlen("PrivateExponent:")) == 0) {
-                    if (got_priv_exponent) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Two PrivateExponent entries");
-                    }
-                    got_priv_exponent = true;
-                    std::string value(line + strlen("PrivateExponent:") + 1);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "PrivateExponent: " << exc.what());
-                    }
-                    int len = static_cast<int>(bin.size());
-                    rsa->d = BN_bin2bn(&bin[0], len, NULL);
-                } else if (strncmp(line, "Prime1:", strlen("Prime1:")) == 0) {
-                    if (got_prime1) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Two Prime1 entries");
-                    }
-                    got_prime1 = true;
-                    std::string value(line + strlen("Prime1:") + 1);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Prime1: " << exc.what());
-                    }
-                    int len = static_cast<int>(bin.size());
-                    rsa->p = BN_bin2bn(&bin[0], len, NULL);
-                } else if (strncmp(line, "Prime2:", strlen("Prime2:")) == 0) {
-                    if (got_prime2) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Two Prime2 entries");
-                    }
-                    got_prime2 = true;
-                    std::string value(line + strlen("Prime2:") + 1);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Prime2: " << exc.what());
-                    }
-                    int len = static_cast<int>(bin.size());
-                    rsa->q = BN_bin2bn(&bin[0], len, NULL);
-                } else if (strncmp(line, "Exponent1:",
-                                   strlen("Exponent1:")) == 0) {
-                    if (got_exponent1) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Two Exponent1 entries");
-                    }
-                    got_exponent1 = true;
-                    std::string value(line + strlen("Exponent1:") + 1);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Exponent1: " << exc.what());
-                    }
-                    int len = static_cast<int>(bin.size());
-                    rsa->dmp1 = BN_bin2bn(&bin[0], len, NULL);
-                } else if (strncmp(line, "Exponent2:",
-                                   strlen("Exponent2:")) == 0) {
-                    if (got_exponent2) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Two Exponent2 entries");
-                    }
-                    got_exponent2 = true;
-                    std::string value(line + strlen("Exponent2:") + 1);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Exponent2: " << exc.what());
-                    }
-                    int len = static_cast<int>(bin.size());
-                    rsa->dmq1 = BN_bin2bn(&bin[0], len, NULL);
-                } else if (strncmp(line, "Coefficient:",
-                                   strlen("Coefficient:")) == 0) {
-                    if (got_coefficient) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Two Coefficient entries");
-                    }
-                    got_coefficient = true;
-                    std::string value(line + strlen("Coefficient:") + 1);
-                    std::vector<uint8_t> bin;
-                    try {
-                        isc::util::encode::decodeBase64(value, bin);
-                    } catch (const BadValue& exc) {
-                        RSA_free(rsa);
-                        fclose(fp);
-                        isc_throw(BadKey, "Coefficient: " << exc.what());
-                    }
-                    int len = static_cast<int>(bin.size());
-                    rsa->iqmp = BN_bin2bn(&bin[0], len, NULL);
-                }
-            }
-            fclose(fp);
-            if (!got_algorithm) {
-                RSA_free(rsa);
-                isc_throw(BadKey, "Missing Algorithm entry");
-            }
-            if (!got_modulus) {
-                RSA_free(rsa);
-                isc_throw(BadKey, "Missing Modulus entry");
-            }
-            if (!got_pub_exponent) {
-                RSA_free(rsa);
-                isc_throw(BadKey, "Missing PublicExponent entry");
-            }
-            if (!got_priv_exponent) {
-                RSA_free(rsa);
-                isc_throw(BadKey, "Missing PrivateExponent entry");
-            }
-            if (!got_prime1) {
-                RSA_free(rsa);
-                isc_throw(BadKey, "Missing Prime1 entry");
-            }
-            if (!got_prime2) {
-                RSA_free(rsa);
-                isc_throw(BadKey, "Missing Prime2 entry");
-            }
-            if (!got_exponent1) {
-                RSA_free(rsa);
-                isc_throw(BadKey, "Missing Exponent1 entry");
-            }
-            if (!got_exponent2) {
-                RSA_free(rsa);
-                isc_throw(BadKey, "Missing Exponent2 entry");
-            }
-            if (!got_coefficient) {
-                RSA_free(rsa);
-                isc_throw(BadKey, "Missing Coefficient entry");
-            }
-            pkey_ = EVP_PKEY_new();
-            if (!pkey_) {
-                RSA_free(rsa);
-                throw std::bad_alloc();
-            }
-            if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
-                RSA_free(rsa);
-                EVP_PKEY_free(pkey_);
-                pkey_ = NULL;
-                isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
-            }
-            // set1 bumped the reference counter
-            RSA_free(rsa);
-        } else if ((kind_ == PUBLIC) && (key_format == BASIC)) {
-            // PKCS#1 PEM file
-            // warn when password not empty
-            FILE* fp = fopen(filename.c_str(), "r");
-            if (!fp) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            RSA* rsa = PEM_read_RSAPublicKey(fp, NULL, 0, NULL);
-            fclose(fp);
-            if (!rsa) {
-                isc_throw(BadKey, "PEM_read_RSAPublicKey");
-            }
-            pkey_ = EVP_PKEY_new();
-            if (!pkey_) {
-                RSA_free(rsa);
-                throw std::bad_alloc();
-            }
-            if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
-                RSA_free(rsa);
-                EVP_PKEY_free(pkey_);
-                pkey_ = NULL;
-                isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
-            }
-            // set1 bumped the reference counter
-            RSA_free(rsa);
-        } else if ((kind_ == PUBLIC) && (key_format == ASN1)) {
-            // SubjectPublicKeyInfo PEM file
-            // warn when password not empty
-            FILE* fp = fopen(filename.c_str(), "r");
-            if (!fp) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            char* pwd = NULL;
-            if (!password.empty()) {
-                pwd = const_cast<char*>(password.c_str());
-            }
-            pkey_ = PEM_read_PUBKEY(fp, NULL, 0, pwd);
-            fclose(fp);
-            if (!pkey_) {
-                isc_throw(BadKey, "PEM_read_PUBKEY");
-            }
-            if (pkey_->type != EVP_PKEY_RSA) {
-                EVP_PKEY_free(pkey_);
-                pkey_ = NULL;
-                isc_throw(BadKey, "not a RSA Public Key");
-            }
-        } else if ((kind_ == PUBLIC) && (key_format == DNS)) {
-            // bind9 .key file (RDATA)
-            // warn when password not empty
-            if ((hash_ != MD5) && (hash_ != SHA1) &&
-                (hash_ != SHA256) && (hash_ != SHA512)) {
-                isc_throw(UnsupportedAlgorithm,
-                          "Not compatible hash algorithm: " <<
-                          static_cast<int>(hash_));
-            }
-            FILE* fp = fopen(filename.c_str(), "r");
-            if (!fp) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            char line[4096];
-            bool found = false;
-            while (fgets(line, sizeof(line), fp)) {
-                if ((line[0] == '\0') || (line[0] == ';')) {
-                    continue;
-                }
-                if (strstr(line, "DNSKEY") == NULL) {
-                    continue;
-                }
-                found = true;
-                if (line[strlen(line) - 1] == '\n') {
-                    line[strlen(line) - 1] = 0;
-                }
-                break;
-            }
-            fclose(fp);
-            if (!found) {
-                isc_throw(BadKey, "Can't find a DNSKEY");
-            }
-            const char b64[] =
-                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
-                "ghijklmnopqrstuvwxyz0123456789+/=";
-            size_t last = strlen(line) - 1;
-            while (strchr(b64, static_cast<int>(line[last])) != NULL) {
-                --last;
-            }
-            const std::string value(line + last + 1);
-            std::vector<uint8_t> bin;
-            try {
-                util::encode::decodeBase64(value, bin);
-            } catch (const BadValue& exc) {
-               isc_throw(BadKey, "Can't decode base64: " << exc.what());
-            }
-            size_t key_len = bin.size();
-            const uint8_t* p = &bin[0];
-            unsigned int e_bytes = *p++;
-            --key_len;
-            if (e_bytes == 0) {
-                if (key_len < 2) {
-                    isc_throw(BadKey,
-                              "Bad RSA Public Key: short exponent length");
-                }
-                e_bytes = (*p++) << 8;
-                e_bytes += *p++;
-                key_len -= 2;
-            }
-            if (key_len < e_bytes) {
-                isc_throw(BadKey, "Bad RSA Public Key: short exponent");
-            }
-            if ((key_len - e_bytes) < 64) {
-                isc_throw(BadKey, "Bad RSA Public Key: too short: " <<
-                          (key_len - e_bytes) * 8);
-            }
-            if ((key_len - e_bytes) > 512) {
-                isc_throw(BadKey, "Bad RSA Public Key: too large: " <<
-                          (key_len - e_bytes) * 8);
-            }
-            RSA* rsa = RSA_new();
-            if (!rsa) {
-                throw std::bad_alloc();
-            }
-            rsa->e = BN_bin2bn(p, e_bytes, NULL);
-            p += e_bytes;
-            key_len -= e_bytes;
-            rsa->n = BN_bin2bn(p, key_len, NULL);
-            if (!rsa->e || !rsa->n) {
-                RSA_free(rsa);
-                throw std::bad_alloc();
-            }
-            pkey_ = EVP_PKEY_new();
-            if (!pkey_) {
-                RSA_free(rsa);
-                throw std::bad_alloc();
-            }
-            if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
-                RSA_free(rsa);
-                EVP_PKEY_free(pkey_);
-                pkey_ = NULL;
-                isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
-            }
-            // set1 bumped the reference counter
-            RSA_free(rsa);
-        } else if (kind_ == PUBLIC) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Public Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((kind_ == CERT) && (key_format == ASN1)) {
-            // Public Key Certificate PEM file
-            // warn when password not empty
-            FILE* fp = fopen(filename.c_str(), "r");
-            if (!fp) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            x509_ = PEM_read_X509(fp, NULL, 0, NULL);
-            fclose(fp);
-            if (!x509_) {
-                isc_throw(BadKey, "PEM_read_X509");
-            }
-            int sig_nid = OBJ_obj2nid(x509_->sig_alg->algorithm);
-            if (hash_ == MD5) {
-                if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.4")) {
-                    X509_free(x509_);
-                    x509_ = NULL;
-                    isc_throw(BadKey, "Require a RSA MD5 certificate");
-                }
-            } else if (hash_ == SHA1) {
-                if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.5")) {
-                    X509_free(x509_);
-                    x509_ = NULL;
-                    isc_throw(BadKey, "Require a RSA SHA1 certificate");
-                }
-            } else if (hash_ == SHA224) {
-                if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.14")) {
-                    X509_free(x509_);
-                    x509_ = NULL;
-                    isc_throw(BadKey, "Require a RSA SHA224 certificate");
-                }
-            } else if (hash_ == SHA256) {
-                if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.11")) {
-                    X509_free(x509_);
-                    x509_ = NULL;
-                    isc_throw(BadKey, "Require a RSA SHA256 certificate");
-                }
-            } else if (hash_ == SHA384) {
-                if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.12")) {
-                    X509_free(x509_);
-                    x509_ = NULL;
-                    isc_throw(BadKey, "Require a RSA SHA384 certificate");
-                }
-            } else if (hash_ == SHA512) {
-                if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.13")) {
-                    X509_free(x509_);
-                    x509_ = NULL;
-                    isc_throw(BadKey, "Require a RSA SHA512 certificate");
-                }
-            } else {
-                X509_free(x509_);
-                x509_ = NULL;
-                isc_throw(UnsupportedAlgorithm,
-                          "Bad hash algorithm for certificate: " <<
-                          static_cast<int>(hash_));
-            }
-            pkey_ = X509_get_pubkey(x509_);
-            if (!pkey_) {
-                X509_free(x509_);
-                x509_ = NULL;
-                isc_throw(BadKey, "X509_get_pubkey");
-            }
-            if (pkey_->type != EVP_PKEY_RSA) {
-                EVP_PKEY_free(pkey_);
-                pkey_ = NULL;
-                X509_free(x509_);
-                x509_ = NULL;
-                isc_throw(BadKey, "not a RSA Public Key");
-            }
-        } else if (kind_ == CERT) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown Public Key Certificate format: " <<
-                      static_cast<int>(key_format));
-        } else {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Key kind: " <<
-                      static_cast<int>(kind_));
-        }
-        mdctx_.reset(new EVP_MD_CTX);
-        EVP_MD_CTX_init(mdctx_.get());
-
-        if (!EVP_DigestInit_ex(mdctx_.get(), md, NULL)) {
-            EVP_MD_CTX_cleanup(mdctx_.get());
-            EVP_PKEY_free(pkey_);
-            pkey_ =NULL;
-            isc_throw(LibraryError, "EVP_DigestInit_ex");
-        }
-    }
-
-    /// @brief Destructor
-    virtual ~RsaAsymImpl() {
-        if (mdctx_) {
-            EVP_MD_CTX_cleanup(mdctx_.get());
-        }
-        if (pkey_) {
-            EVP_PKEY_free(pkey_);
-            pkey_ = NULL;
-        }
-        if (x509_) {
-            X509_free(x509_);
-            x509_ = NULL;
-        }
-    }
-
-    /// @brief Returns the AsymAlgorithm of the object
-    AsymAlgorithm getAsymAlgorithm() const {
-        return (algo_);
-    }
-
-    /// @brief Returns the HashAlgorithm of the object
-    HashAlgorithm getHashAlgorithm() const {
-        return (hash_);
-    }
-
-    /// @brief Returns the AsymKeyKind of the object
-    AsymKeyKind getAsymKeyKind() const {
-        return (kind_);
-    }
-
-    /// @brief Returns the key size in bits
-    ///
-    size_t getKeySize() const {
-        return (static_cast<size_t>(EVP_PKEY_bits(pkey_)));
-    }
-
-    /// @brief Returns the output size of the signature
-    ///
-    /// \param sig_format The signature binary format
-    size_t getSignatureLength(const AsymFormat sig_format) const {
-        switch (sig_format) {
-        case BASIC:
-        case ASN1:
-        case DNS:
-            // In all cases a big integer of the size of n
-            return (static_cast<size_t>(EVP_PKEY_size(pkey_)));
-        default:
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Signature format: " <<
-                      static_cast<int>(sig_format));
-        }
-    }           
-
-    /// @brief Add data to digest
-    ///
-    /// See @ref isc::cryptolink::AsymBase::update() for details.
-    void update(const void* data, const size_t len) {
-        if (!EVP_DigestUpdate(mdctx_.get(), data, len)) {
-            isc_throw(LibraryError, "EVP_DigestUpdate");
-        }
-    }
-
-    /// @brief Calculate the final signature
-    ///
-    /// See @ref isc::cryptolink::AsymBase::sign() for details.
-    void sign(isc::util::OutputBuffer& result, size_t len,
-              const AsymFormat sig_format) {
-        unsigned int size = getSignatureLength(sig_format);
-        ossl::SecBuf<unsigned char> sig(size);
-        if (!EVP_SignFinal(mdctx_.get(), &sig[0], &size, pkey_)) {
-            isc_throw(LibraryError, "EVP_SignFinal");
-        }
-        if (len > size) {
-            len = size;
-        }
-        result.writeData(&sig[0], len);
-    }
-
-    /// @brief Calculate the final signature
-    ///
-    /// See @ref isc::cryptolink::AsymBase::sign() for details.
-    void sign(void* result, size_t len, const AsymFormat sig_format) {
-        unsigned int size = getSignatureLength(sig_format);
-        ossl::SecBuf<unsigned char> sig(size);
-        if (!EVP_SignFinal(mdctx_.get(), &sig[0], &size, pkey_)) {
-            isc_throw(LibraryError, "EVP_SignFinal");
-        }
-        if (len > size) {
-            len = size;
-        }
-        std::memcpy(result, &sig[0], len);
-    }
-
-    /// @brief Calculate the final signature
-    ///
-    /// See @ref isc::cryptolink::AsymBase::sign() for details.
-    std::vector<uint8_t> sign(size_t len, const AsymFormat sig_format) {
-        unsigned int size = getSignatureLength(sig_format);
-        ossl::SecBuf<unsigned char> sig(size);
-        if (!EVP_SignFinal(mdctx_.get(), &sig[0], &size, pkey_)) {
-            isc_throw(LibraryError, "EVP_SignFinal");
-        }
-        // resize to min(len, size)
-        sig.resize(len < size ? len : size);
-        return (std::vector<uint8_t>(sig.begin(), sig.end()));
-    }  
-
-    /// @brief Verify an existing signature
-    ///
-    /// See @ref isc::cryptolink::AsymBase::verify() for details.
-    bool verify(const void* sig, size_t len, const AsymFormat sig_format) {
-        size_t size = getSignatureLength(sig_format);
-        if (len != size) {
-            return false;
-        }
-        unsigned char* sigbuf =
-            reinterpret_cast<unsigned char*>(const_cast<void*>(sig));
-        unsigned int siglen = static_cast<unsigned int>(len);
-        int status = EVP_VerifyFinal(mdctx_.get(), sigbuf, siglen, pkey_);
-        switch (status) {
-        case 1:
-            return true;
-        case 0:
-            return false;
-        case -1:
-        default:
-            isc_throw(LibraryError, "EVP_VerifyFinal");
-        }
-    }
-
-    /// @brief Clear the crypto state and go back to the initial state
-    /// (must be called before reusing an Asym object)
-    void clear() {
-        if (mdctx_) {
-            EVP_MD_CTX_cleanup(mdctx_.get());
-        } else {
-            mdctx_.reset(new EVP_MD_CTX);
-        }
-        EVP_MD_CTX_init(mdctx_.get());
-        const EVP_MD* md = ossl::getHashAlgorithm(hash_);
-        if (md == 0) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown hash algorithm: " <<
-                      static_cast<int>(hash_));
-        }
-        if (!EVP_DigestInit_ex(mdctx_.get(), md, NULL)) {
-            EVP_MD_CTX_cleanup(mdctx_.get());
-            EVP_PKEY_free(pkey_);
-            pkey_ =NULL;
-            isc_throw(LibraryError, "EVP_DigestInit_ex");
-        }
-    }
-
-    /// @brief Export the key value (binary)
-    ///
-    /// See @ref isc::cryptolink::AsymBase::exportkey() for details
-    std::vector<uint8_t> exportkey(const AsymKeyKind key_kind,
-                                   const AsymFormat key_format) const {
-        if ((key_kind == PRIVATE) && (key_format == BASIC)) {
-            // PKCS#1 Private Key
-            if (kind_ != PRIVATE) {
-                isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
-            }
-            RSA* rsa = EVP_PKEY_get1_RSA(pkey_);
-            if (!rsa) {
-                isc_throw(LibraryError, "EVP_PKEY_get1_RSA");
-            }
-            int len = i2d_RSAPrivateKey(rsa, NULL);
-            if (len < 0) {
-                RSA_free(rsa);
-                isc_throw(LibraryError, "i2d_RSAPrivateKey 0");
-            }
-            std::vector<uint8_t> der(static_cast<size_t>(len));
-            unsigned char* p = &der[0];
-            len = i2d_RSAPrivateKey(rsa, &p);
-            RSA_free(rsa);
-            if (len != static_cast<int>(der.size())) {
-                isc_throw(LibraryError, "i2d_RSAPrivateKey");
-            }
-            return der;
-        } else if (key_kind == PRIVATE) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Private Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((key_kind == PUBLIC) && (key_format == BASIC)) {
-            // PKCS#1 Public Key
-            RSA* rsa = EVP_PKEY_get1_RSA(pkey_);
-            if (!rsa) {
-                isc_throw(LibraryError, "EVP_PKEY_get1_RSA");
-            }
-            int len = i2d_RSAPublicKey(rsa, NULL);
-            if (len < 0) {
-                RSA_free(rsa);
-                isc_throw(LibraryError, "i2d_RSAPublicKey 0");
-            }
-            std::vector<uint8_t> der(static_cast<size_t>(len));
-            unsigned char* p = &der[0];
-            len = i2d_RSAPublicKey(rsa, &p);
-            RSA_free(rsa);
-            if (len != static_cast<int>(der.size())) {
-                isc_throw(LibraryError, "i2d_RSAPublicKey");
-            }
-            return der;
-        } else if ((key_kind == PUBLIC) && (key_format == ASN1)) {
-            // SubjectPublicKeyInfo
-            RSA* rsa = EVP_PKEY_get1_RSA(pkey_);
-            if (!rsa) {
-                isc_throw(LibraryError, "EVP_PKEY_get1_RSA");
-            }
-            int len = i2d_RSA_PUBKEY(rsa, NULL);
-            if (len < 0) {
-                RSA_free(rsa);
-                isc_throw(LibraryError, "i2d_RSA_PUBKEY 0");
-            }
-            std::vector<uint8_t> der(static_cast<size_t>(len));
-            unsigned char* p = &der[0];
-            len = i2d_RSA_PUBKEY(rsa, &p);
-            RSA_free(rsa);
-            if (len != static_cast<int>(der.size())) {
-                isc_throw(LibraryError, "i2d_RSA_PUBKEY");
-            }
-            return der;
-        } else if ((key_kind == PUBLIC) && (key_format == DNS)) {
-            // RFC 3110 DNS wire format
-            RSA* rsa = EVP_PKEY_get1_RSA(pkey_);
-            if (!rsa) {
-                isc_throw(LibraryError, "EVP_PKEY_get1_RSA");
-            }
-            size_t e_bytes = BN_num_bytes(rsa->e);
-            size_t mod_bytes = BN_num_bytes(rsa->n);
-            size_t x_bytes = 1;
-            if (e_bytes >= 256) {
-                x_bytes += 2;
-            }
-            std::vector<uint8_t> rdata(x_bytes + e_bytes + mod_bytes);
-            if (e_bytes < 256) {
-                rdata[0] = e_bytes;
-            } else {
-                rdata[0] = 0;
-                rdata[1] = (e_bytes >> 8) & 0xff;
-                rdata[2] = e_bytes & 0xff;
-            }
-            BN_bn2bin(rsa->e, &rdata[x_bytes]);
-            BN_bn2bin(rsa->n, &rdata[x_bytes + e_bytes]);
-            RSA_free(rsa);
-            return rdata;
-        } else if (key_kind == PUBLIC) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Public Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((key_kind == CERT) && (key_format == ASN1)) {
-            // X.509 Public Key Certificate
-            if (kind_ != CERT) {
-                isc_throw(UnsupportedAlgorithm, "Have no Certificate");
-            }
-            int len = i2d_X509(x509_, NULL);
-            if (len < 0) {
-                isc_throw(LibraryError, "i2d_X509 0");
-            }
-            std::vector<uint8_t> ber(static_cast<size_t>(len));
-            unsigned char* p = &ber[0];
-            len = i2d_X509(x509_, &p);
-            if (len != static_cast<int>(ber.size())) {
-                isc_throw(LibraryError, "i2d_X509");
-            }
-            return ber;
-        } else if (key_kind == CERT) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown Certificate format: " <<
-                      static_cast<int>(key_format));
-        } else {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Key kind: " <<
-                      static_cast<int>(key_kind));
-        }
-    }
-
-    /// @brief Export the key value (file)
-    ///
-    /// See @ref isc::cryptolink::AsymBase::exportkey() for details
-    void exportkey(const std::string& filename,
-                   const std::string& password,
-                   const AsymKeyKind key_kind,
-                   const AsymFormat key_format) const {
-        if ((key_kind == PRIVATE) && (key_format == ASN1)) {
-            // PKCS#8 Private Key PEM file
-            if (kind_ != PRIVATE) {
-                isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
-            }
-            char* pwd = NULL;
-            const EVP_CIPHER* enc = NULL;
-            if (!password.empty()) {
-                pwd = const_cast<char*>(password.c_str());
-                enc = EVP_des_ede3_cbc();
-                if (!enc) {
-                    isc_throw(LibraryError, "EVP_des_ede3_cbc");
-                }
-            }
-            FILE* fp = fopen(filename.c_str(), "w");
-            if (!fp) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            if (!PEM_write_PKCS8PrivateKey(fp, pkey_, enc, pwd,
-                                           static_cast<int>(password.size()),
-                                           0, NULL)) {
-                fclose(fp);
-                isc_throw(LibraryError, "PEM_write_PKCS8PrivateKey");
-            }
-            fclose(fp);
-        } else if ((key_kind == PRIVATE) && (key_format == DNS)) {
-            //  bind9 .private file
-            if (kind_ != PRIVATE) {
-                isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
-            }
-            if ((hash_ != MD5) && (hash_ != SHA1) &&
-                (hash_ != SHA256) && (hash_ != SHA512)) {
-                isc_throw(UnsupportedAlgorithm,
-                          "Not compatible hash algorithm: " <<
-                          static_cast<int>(hash_));
-            }
-            FILE* fp = fopen(filename.c_str(), "w");
-            if (!fp) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            RSA* rsa = EVP_PKEY_get1_RSA(pkey_);
-            if (!rsa) {
-                fclose(fp);
-                isc_throw(LibraryError, "EVP_PKEY_get1_RSA");
-            }
-            fprintf(fp, "Private-key-format: v1.2\n");
-            if (hash_ == MD5) {
-                fprintf(fp, "Algorithm: 1 (RSA)\n");
-            } else if (hash_ == SHA1) {
-                fprintf(fp, "Algorithm: 5 (RSASHA1)\n");
-            } else if (hash_ == SHA256) {
-                fprintf(fp, "Algorithm: 8 (RSASHA256)\n");
-            } else if (hash_ == SHA512) {
-                fprintf(fp, "Algorithm: 10 (RSASHA512)\n");
-            }
-            std::vector<uint8_t> bin;
-            bin.resize(BN_num_bytes(rsa->n));
-            BN_bn2bin(rsa->n, &bin[0]);
-            fprintf(fp, "Modulus: %s\n",
-                    util::encode::encodeBase64(bin).c_str());
-            bin.resize(BN_num_bytes(rsa->e));
-            BN_bn2bin(rsa->e, &bin[0]);
-            fprintf(fp, "PublicExponent: %s\n",
-                    util::encode::encodeBase64(bin).c_str());
-            bin.resize(BN_num_bytes(rsa->d));
-            BN_bn2bin(rsa->d, &bin[0]);
-            fprintf(fp, "PrivateExponent: %s\n",
-                    util::encode::encodeBase64(bin).c_str());
-            bin.resize(BN_num_bytes(rsa->p));
-            BN_bn2bin(rsa->p, &bin[0]);
-            fprintf(fp, "Prime1: %s\n",
-                    util::encode::encodeBase64(bin).c_str());
-            bin.resize(BN_num_bytes(rsa->q));
-            BN_bn2bin(rsa->q, &bin[0]);
-            fprintf(fp, "Prime2: %s\n",
-                    util::encode::encodeBase64(bin).c_str());
-            bin.resize(BN_num_bytes(rsa->dmp1));
-            BN_bn2bin(rsa->dmp1, &bin[0]);
-            fprintf(fp, "Exponent1: %s\n",
-                    util::encode::encodeBase64(bin).c_str());
-            bin.resize(BN_num_bytes(rsa->dmq1));
-            BN_bn2bin(rsa->dmq1, &bin[0]);
-            fprintf(fp, "Exponent2: %s\n",
-                    util::encode::encodeBase64(bin).c_str());
-            bin.resize(BN_num_bytes(rsa->iqmp));
-            BN_bn2bin(rsa->iqmp, &bin[0]);
-            fprintf(fp, "Coefficient: %s\n",
-                    util::encode::encodeBase64(bin).c_str());
-            fclose(fp);
-            RSA_free(rsa);
-        } else if (key_kind == PRIVATE) {
-            if (kind_ != PRIVATE) {
-                isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
-            }
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Private Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((key_kind == PUBLIC) && (key_format == BASIC)) {
-            // PKCS#1 PEM file
-            // warn when password not empty
-            FILE* fp = fopen(filename.c_str(), "w");
-            if (!fp) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            RSA* rsa = EVP_PKEY_get1_RSA(pkey_);
-            if (!rsa) {
-                fclose(fp);
-                isc_throw(LibraryError, "EVP_PKEY_get1_RSA");
-            }
-            if (!PEM_write_RSAPublicKey(fp, rsa)) {
-                fclose(fp);
-                RSA_free(rsa);
-                isc_throw(LibraryError, "PEM_write_RSAPublicKey");
-            }
-            fclose(fp);
-            RSA_free(rsa);
-        } else if ((key_kind == PUBLIC) && (key_format == ASN1)) {
-            // SubjectPublicKeyInfo PEM file
-            // warn when password not empty
-            FILE* fp = fopen(filename.c_str(), "w");
-            if (!fp) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            if (!PEM_write_PUBKEY(fp, pkey_)) {
-                fclose(fp);
-                isc_throw(LibraryError, "PEM_write_PUBKEY");
-            }
-            fclose(fp);
-        }  else if ((key_kind == PUBLIC) && (key_format == DNS)) {
-            // bind9 .key file (RDATA)
-            // warn when password not empty
-            std::vector<uint8_t> bin = exportkey(key_kind, key_format);
-            FILE* fp = fopen(filename.c_str(), "w");
-            if (!fp) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            fprintf(fp, "; DNSKEY RDATA: %s\n",
-                    util::encode::encodeBase64(bin).c_str());
-            fclose(fp);
-        } else if (key_kind == PUBLIC) {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Public Key format: " <<
-                      static_cast<int>(key_format));
-        } else if ((key_kind == CERT) && (key_format == ASN1)) {
-            // Public Key Certificate PEM file
-            // warn when password not empty
-            if (!x509_) {
-                isc_throw(UnsupportedAlgorithm, "Have no Certificate");
-            }
-            FILE* fp = fopen(filename.c_str(), "w");
-            if (!fp) {
-                isc_throw(BadKey, "Can't open file: " << filename);
-            }
-            if (!PEM_write_X509(fp, x509_)) {
-                fclose(fp);
-                isc_throw(LibraryError, "PEM_write_X509");
-            }
-            fclose(fp);
-        } else if (key_kind == CERT) {
-            if (!x509_) {
-                isc_throw(UnsupportedAlgorithm, "Have no Certificate");
-            }
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown Certificate format: " <<
-                      static_cast<int>(key_format));
-        } else {
-            isc_throw(UnsupportedAlgorithm,
-                      "Unknown RSA Key kind: " <<
-                      static_cast<int>(key_kind));
-        }
-    }
-
-    /// @brief Check the validity
-    ///
-    /// See @ref isc::cryptolink::AsymBase::validate() for details
-    bool validate() const {
-        RSA* rsa;
-        X509_STORE* store;
-        X509_STORE_CTX* ctx;
-        int status;
-        switch (kind_) {
-        case PUBLIC:
-            // what to do?
-            return true;
-        case PRIVATE:
-            rsa = EVP_PKEY_get1_RSA(pkey_);
-            if (!rsa) {
-                return false;
-            }
-            status = RSA_check_key(rsa);
-            RSA_free(rsa);
-            return (status == 1);
-        case CERT:
-            store = X509_STORE_new();
-            if (!store) {
-                return false;
-            }
-            if (!X509_STORE_add_cert(store, x509_)) {
-                X509_STORE_free(store);
-                store = NULL;
-                return false;
-            }
-            ctx = X509_STORE_CTX_new();
-            if (!ctx) {
-                X509_STORE_free(store);
-                store = NULL;
-                return false;
-            }
-            if (!X509_STORE_CTX_init(ctx, store, x509_, NULL)) {
-                X509_STORE_CTX_free(ctx);
-                ctx = NULL;
-                X509_STORE_free(store);
-                store = NULL;
-                return false;
-            }
-            // By default OpenSSL skips self-signatures
-            X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CHECK_SS_SIGNATURE);
-            status = X509_verify_cert(ctx);
-            // text version of status available by
-            // X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx))
-            X509_STORE_CTX_free(ctx);
-            ctx = NULL;
-            X509_STORE_free(store);
-            store = NULL;
-            if (status == 1) {
-                return true;
-            }
-            return false;
-        default:
-            return false;
-        }
-    }
-
-    /// @brief Compare two keys
-    ///
-    /// See @ref isc::cryptolink::Asym::compare() for details
-    bool compare(const RsaAsymImpl* other, const AsymKeyKind key_kind) const {
-        if (!other || (other->algo_ != RSA_)) {
-            return false;
-        }
-        int status;
-        switch (key_kind) {
-        case CERT:
-            // Special case for cert - cert
-            if ((kind_ == CERT) && (other->kind_ == CERT)) {
-                return (X509_cmp(x509_, other->x509_) == 0);
-            }
-            // At least one should be a cert
-            if ((kind_ != CERT) && (other->kind_ != CERT)) {
-                return false;
-            }
-            // For all other cases just compare public keys
-            // Falls into
-        case PUBLIC:
-            if ((kind_ != PUBLIC) &&
-                (kind_ != PRIVATE) &&
-                (kind_ != CERT)) {
-                return false;
-            }
-            if ((other->kind_ != PUBLIC) &&
-                (other->kind_ != PRIVATE) &&
-                (other->kind_ != CERT)) {
-                return false;
-            }
-            status = EVP_PKEY_cmp(pkey_, other->pkey_);
-            switch (status) {
-            case 1:
-                // match
-                return true;
-            case 0:
-                // don't match
-                return false;
-            case -1:
-                // different types
-                return false;
-            case -2:
-                // not supported
-                return false;
-            }
-            return false;
-        case PRIVATE:
-            if ((kind_ != PRIVATE) || (other->kind_ != PRIVATE)) {
-                return false;
-            }
-            // If public keys match so private too
-            status = EVP_PKEY_cmp(pkey_, other->pkey_);
-            switch (status) {
-            case 1:
-                // match
-                return true;
-            case 0:
-                // don't match
-                return false;
-            case -1:
-                // different types
-                return false;
-            case -2:
-                // not supported
-                return false;
-            }
-            return false;
-        default:
-            return false;
-        }
-    }
-
-private:
-    /// @brief The asymmetrical cryptography algorithm
-    AsymAlgorithm algo_;
-    /// @brief The hash algorithm
-    HashAlgorithm hash_;
-    /// @brief The key kind
-    AsymKeyKind kind_;
-    /// @brief The protected pointer to the OpenSSL EVP_MD_CTX structure
-    boost::scoped_ptr<EVP_MD_CTX> mdctx_;
-    /// @brief The raw pointer to the OpenSSL EVP_PKEY structure
-    /// There is no EVP_PKEY_init() or EVP_PKEY_cleanup() so
-    /// a smart pointer cannot be used.
-    EVP_PKEY* pkey_;
-    /// @brief The raw pointer to the OpenSSL X509 structure
-    /// There is no X509_init() or X509_cleanup() so
-    /// a smart pointer cannot be used.
-    X509* x509_;
-};
-
 Asym::Asym(const void* key, size_t key_len,
            const AsymAlgorithm asym_algorithm,
            const HashAlgorithm hash_algorithm,
diff --git a/src/lib/cryptolink/openssl_rsa.cc b/src/lib/cryptolink/openssl_rsa.cc
new file mode 100644 (file)
index 0000000..8958cc3
--- /dev/null
@@ -0,0 +1,1370 @@
+// Copyright (C) 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cryptolink.h>
+#include <cryptolink/crypto_asym.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+
+#include <util/encode/base64.h>
+#include <cryptolink/openssl_common.h>
+#include <cryptolink/openssl_rsa.h>
+
+#include <cstdio>
+#include <cstring>
+
+namespace isc {
+namespace cryptolink {
+
+/// @brief Constructor from a key, asym and hash algorithm,
+///        key kind and key binary format
+RsaAsymImpl::RsaAsymImpl(const void* key, size_t key_len,
+                        const HashAlgorithm hash_algorithm,
+                        const AsymKeyKind key_kind,
+                        const AsymFormat key_format) {
+    algo_ = RSA_;
+    hash_ = hash_algorithm;
+    kind_ = key_kind;
+    pkey_ = NULL;
+    x509_ = NULL;
+    const EVP_MD* md = ossl::getHashAlgorithm(hash_);
+    if (md == 0) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown hash algorithm: " << static_cast<int>(hash_));
+    }
+    if (key_len == 0) {
+        isc_throw(BadKey, "Bad RSA " <<
+                  (kind_ != CERT ? "key" : "cert") << " length: 0");
+    }
+
+    if ((kind_ == PRIVATE) && (key_format == BASIC)) {
+        // PKCS#1 Private Key
+        const unsigned char* p = reinterpret_cast<const unsigned char*>(key);
+        RSA* rsa = d2i_RSAPrivateKey(NULL, &p, static_cast<long>(key_len));
+        if (!rsa) {
+            isc_throw(BadKey, "d2i_RSAPrivateKey");
+        }
+        pkey_ = EVP_PKEY_new();
+        if (!pkey_) {
+            RSA_free(rsa);
+            throw std::bad_alloc();
+        }
+        if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
+            RSA_free(rsa);
+            EVP_PKEY_free(pkey_);
+            pkey_ = NULL;
+            isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
+        }
+        // set1 bumped the reference counter
+        RSA_free(rsa);
+    } else if (kind_ == PRIVATE) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Private Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((kind_ == PUBLIC) && (key_format == BASIC)) {
+        // PKCS#1 Public Key
+        const unsigned char* p = reinterpret_cast<const unsigned char*>(key);
+        RSA* rsa = d2i_RSAPublicKey(NULL, &p, static_cast<long>(key_len));
+        if (!rsa) {
+            isc_throw(BadKey, "d2i_RSAPublicKey");
+        }
+        pkey_ = EVP_PKEY_new();
+        if (!pkey_) {
+            RSA_free(rsa);
+            throw std::bad_alloc();
+        }
+        if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
+            RSA_free(rsa);
+            EVP_PKEY_free(pkey_);
+            pkey_ = NULL;
+            isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
+        }
+        // set1 bumped the reference counter
+        RSA_free(rsa);
+    } else if ((kind_ == PUBLIC) && (key_format == ASN1)) {
+        // SubjectPublicKeyInfo
+        const unsigned char* p = reinterpret_cast<const unsigned char*>(key);
+        RSA* rsa = d2i_RSA_PUBKEY(NULL, &p, static_cast<long>(key_len));
+        if (!rsa) {
+            isc_throw(BadKey, "d2i_RSA_PUBKEY");
+        }
+        pkey_ = EVP_PKEY_new();
+        if (!pkey_) {
+            RSA_free(rsa);
+            throw std::bad_alloc();
+        }
+        if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
+            RSA_free(rsa);
+            EVP_PKEY_free(pkey_);
+            pkey_ = NULL;
+            isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
+        }
+        // set1 bumped the reference counter
+        RSA_free(rsa);
+    } else if ((kind_ == PUBLIC) && (key_format == DNS)) {
+        // RFC 3110 DNS wire format
+        // key_len == 0 was already checked
+        const uint8_t* p = reinterpret_cast<const uint8_t*>(key);
+        unsigned int e_bytes = *p++;
+        --key_len;
+        if (e_bytes == 0) {
+            if (key_len < 2) {
+                isc_throw(BadKey, "Bad RSA Public Key: short exponent length");
+            }
+            e_bytes = (*p++) << 8;
+            e_bytes += *p++;
+            key_len -= 2;
+        }
+        if (key_len < e_bytes) {
+            isc_throw(BadKey, "Bad RSA Public Key: short exponent");
+        }
+        if ((key_len - e_bytes) < 64) {
+            isc_throw(BadKey, "Bad RSA Public Key: too short: " <<
+                      (key_len - e_bytes) * 8);
+        }
+        if ((key_len - e_bytes) > 512) {
+            isc_throw(BadKey, "Bad RSA Public Key: too large: " <<
+                      (key_len - e_bytes) * 8);
+        }
+        RSA* rsa = RSA_new();
+        if (!rsa) {
+            throw std::bad_alloc();
+        }
+        rsa->e = BN_bin2bn(p, e_bytes, NULL);
+        p += e_bytes;
+        key_len -= e_bytes;
+        rsa->n = BN_bin2bn(p, key_len, NULL);
+        if (!rsa->e || !rsa->n) {
+            RSA_free(rsa);
+            throw std::bad_alloc();
+        }
+        pkey_ = EVP_PKEY_new();
+        if (!pkey_) {
+            RSA_free(rsa);
+            throw std::bad_alloc();
+        }
+        if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
+            RSA_free(rsa);
+            EVP_PKEY_free(pkey_);
+            pkey_ = NULL;
+            isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
+        }
+        // set1 bumped the reference counter
+        RSA_free(rsa);
+    } else if (kind_ == PUBLIC) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Public Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((kind_ == CERT) && (key_format == ASN1)) {
+        // X.509 Public Key Certificate
+        const unsigned char* p = reinterpret_cast<const unsigned char*>(key);
+        x509_ = d2i_X509(NULL, &p, static_cast<long>(key_len));
+        if (!x509_) {
+            isc_throw(BadKey, "d2i_X509");
+        }
+        int sig_nid = OBJ_obj2nid(x509_->sig_alg->algorithm);
+        if (hash_ == MD5) {
+            if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.4")) {
+                X509_free(x509_);
+                x509_ = NULL;
+                isc_throw(BadKey, "Require a RSA MD5 certificate");
+            }
+        } else if (hash_ == SHA1) {
+            if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.5")) {
+                X509_free(x509_);
+                x509_ = NULL;
+                isc_throw(BadKey, "Require a RSA SHA1 certificate");
+            }
+        } else if (hash_ == SHA224) {
+            if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.14")) {
+                X509_free(x509_);
+                x509_ = NULL;
+                isc_throw(BadKey, "Require a RSA SHA224 certificate");
+            }
+        } else if (hash_ == SHA256) {
+            if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.11")) {
+                X509_free(x509_);
+                x509_ = NULL;
+                isc_throw(BadKey, "Require a RSA SHA256 certificate");
+            }
+        } else if (hash_ == SHA384) {
+            if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.12")) {
+                X509_free(x509_);
+                x509_ = NULL;
+                isc_throw(BadKey, "Require a RSA SHA384 certificate");
+            }
+        } else if (hash_ == SHA512) {
+            if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.13")) {
+                X509_free(x509_);
+                x509_ = NULL;
+                isc_throw(BadKey, "Require a RSA SHA512 certificate");
+            }
+        } else {
+            X509_free(x509_);
+            x509_ = NULL;
+            isc_throw(UnsupportedAlgorithm,
+                      "Bad hash algorithm for certificate: " <<
+                      static_cast<int>(hash_));
+        }
+        pkey_ = X509_get_pubkey(x509_);
+        if (!pkey_) {
+            X509_free(x509_);
+            x509_ = NULL;
+            isc_throw(BadKey, "X509_get_pubkey");
+        }
+        if (pkey_->type != EVP_PKEY_RSA) {
+            EVP_PKEY_free(pkey_);
+            pkey_ = NULL;
+            X509_free(x509_);
+            x509_ = NULL;
+            isc_throw(BadKey, "not a RSA Public Key");
+        }
+    } else if (kind_ == CERT) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown Certificate format: " <<
+                  static_cast<int>(key_format));
+    } else {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Key kind: " << static_cast<int>(kind_));
+    }
+
+    mdctx_.reset(new EVP_MD_CTX);
+    EVP_MD_CTX_init(mdctx_.get());
+
+    if (!EVP_DigestInit_ex(mdctx_.get(), md, NULL)) {
+        EVP_MD_CTX_cleanup(mdctx_.get());
+        EVP_PKEY_free(pkey_);
+        pkey_ =NULL;
+        isc_throw(LibraryError, "EVP_DigestInit_ex");
+    }
+}
+
+/// @brief Constructor from a key file with password,
+///        asym and hash algorithm, key kind and key binary format
+RsaAsymImpl::RsaAsymImpl(const std::string& filename,
+                        const std::string& password,
+                        const HashAlgorithm hash_algorithm,
+                        const AsymKeyKind key_kind,
+                        const AsymFormat key_format) {
+    algo_ = RSA_;
+    hash_ = hash_algorithm;
+    kind_ = key_kind;
+    pkey_ = NULL;
+    x509_ = NULL;
+    const EVP_MD* md = ossl::getHashAlgorithm(hash_);
+    if (md == 0) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown hash algorithm: " << static_cast<int>(hash_));
+    }
+
+    if ((kind_ == PRIVATE) &&
+        ((key_format == BASIC) || (key_format == ASN1))) {
+        // PKCS#1 or PKCS#8 Private Key PEM file
+        FILE* fp = fopen(filename.c_str(), "r");
+        if (!fp) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        char* pwd = NULL;
+        if (!password.empty()) {
+            pwd = const_cast<char*>(password.c_str());
+        }
+        pkey_ = PEM_read_PrivateKey(fp, NULL, 0, pwd);
+        fclose(fp);
+        if (!pkey_) {
+            isc_throw(BadKey, "PEM_read_PrivateKey");
+        }
+        if (pkey_->type != EVP_PKEY_RSA) {
+            EVP_PKEY_free(pkey_);
+            pkey_ = NULL;
+            isc_throw(BadKey, "not a RSA Private Key");
+        }
+    } else if ((kind_ == PRIVATE) && (key_format == DNS)) {
+        // bind9 .private file
+        // warn when password not empty
+        if ((hash_ != MD5) && (hash_ != SHA1) &&
+            (hash_ != SHA256) && (hash_ != SHA512)) {
+            isc_throw(UnsupportedAlgorithm,
+                      "Not compatible hash algorithm: " <<
+                      static_cast<int>(hash_));
+        }
+        FILE* fp = fopen(filename.c_str(), "r");
+        if (!fp) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        bool got_algorithm = false;
+        bool got_modulus = false;
+        bool got_pub_exponent = false;
+        bool got_priv_exponent = false;
+        bool got_prime1 = false;
+        bool got_prime2 = false;
+        bool got_exponent1 = false;
+        bool got_exponent2 = false;
+        bool got_coefficient = false;
+        RSA* rsa = RSA_new();
+        char line[4096];
+        while (fgets(line, sizeof(line), fp)) {
+            if (strncmp(line, "Algorithm:", strlen("Algorithm:")) == 0) {
+                if (got_algorithm) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Two Algorithm entries");
+                }
+                got_algorithm = true;
+                std::string value(line + strlen("Algorithm:") + 1);
+                int alg = std::atoi(value.c_str());
+                if (alg == 1) {
+                    // RSAMD5
+                    if (hash_ != MD5) {
+                        RSA_free(rsa);
+                        fclose(fp);
+                        isc_throw(BadKey, "Require a RSA MD5 key");
+                    }
+                } else if ((alg == 5) || (alg == 7)) {
+                    // RSASHA1 or RSASHA1-NSEC3-SHA1
+                    if (hash_ != SHA1) {
+                        RSA_free(rsa);
+                        fclose(fp);
+                        isc_throw(BadKey, "Require a RSA SHA1 key");
+                    }
+                } else if (alg == 8) {
+                    // RSASHA256
+                    if (hash_ != SHA256) {
+                        RSA_free(rsa);
+                        fclose(fp);
+                        isc_throw(BadKey, "Require a RSA SHA256 key");
+                    }
+                } else if (alg == 10) {
+                    // RSASHA512
+                    if (hash_ != SHA512) {
+                        RSA_free(rsa);
+                        fclose(fp);
+                        isc_throw(BadKey, "Require a RSA SHA512 key");
+                    }
+                } else {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Bad Algorithm: " << alg);
+                }
+            } else if (strncmp(line, "Modulus:", strlen("Modulus:")) == 0) {
+                if (got_modulus) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Two Modulus entries");
+                }
+                got_modulus = true;
+                std::string value(line + strlen("Modulus:") + 1);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Modulus: " << exc.what());
+                }
+                int len = static_cast<int>(bin.size());
+                rsa->n = BN_bin2bn(&bin[0], len, NULL);
+          } else if (strncmp(line, "PublicExponent:",
+                            strlen("PublicExponent:")) == 0) {
+                if (got_pub_exponent) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Two PublicExponent entries");
+                }
+                got_pub_exponent = true;
+                std::string value(line + strlen("PublicExponent:") + 1);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "PublicExponent: " << exc.what());
+                }
+                int len = static_cast<int>(bin.size());
+                rsa->e = BN_bin2bn(&bin[0], len, NULL);
+            } else if (strncmp(line, "PrivateExponent:",
+                               strlen("PrivateExponent:")) == 0) {
+                if (got_priv_exponent) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Two PrivateExponent entries");
+                }
+                got_priv_exponent = true;
+                std::string value(line + strlen("PrivateExponent:") + 1);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "PrivateExponent: " << exc.what());
+                }
+                int len = static_cast<int>(bin.size());
+                rsa->d = BN_bin2bn(&bin[0], len, NULL);
+            } else if (strncmp(line, "Prime1:", strlen("Prime1:")) == 0) {
+                if (got_prime1) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Two Prime1 entries");
+                }
+                got_prime1 = true;
+                std::string value(line + strlen("Prime1:") + 1);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Prime1: " << exc.what());
+                }
+                int len = static_cast<int>(bin.size());
+                rsa->p = BN_bin2bn(&bin[0], len, NULL);
+            } else if (strncmp(line, "Prime2:", strlen("Prime2:")) == 0) {
+                if (got_prime2) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Two Prime2 entries");
+                }
+                got_prime2 = true;
+                std::string value(line + strlen("Prime2:") + 1);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Prime2: " << exc.what());
+                }
+                int len = static_cast<int>(bin.size());
+                rsa->q = BN_bin2bn(&bin[0], len, NULL);
+            } else if (strncmp(line, "Exponent1:",
+                              strlen("Exponent1:")) == 0) {
+                if (got_exponent1) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Two Exponent1 entries");
+                }
+                got_exponent1 = true;
+                std::string value(line + strlen("Exponent1:") + 1);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Exponent1: " << exc.what());
+                }
+                int len = static_cast<int>(bin.size());
+                rsa->dmp1 = BN_bin2bn(&bin[0], len, NULL);
+            } else if (strncmp(line, "Exponent2:",
+                               strlen("Exponent2:")) == 0) {
+                if (got_exponent2) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Two Exponent2 entries");
+                }
+                got_exponent2 = true;
+                std::string value(line + strlen("Exponent2:") + 1);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Exponent2: " << exc.what());
+                }
+                int len = static_cast<int>(bin.size());
+                rsa->dmq1 = BN_bin2bn(&bin[0], len, NULL);
+            } else if (strncmp(line, "Coefficient:",
+                               strlen("Coefficient:")) == 0) {
+                if (got_coefficient) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Two Coefficient entries");
+                }
+                got_coefficient = true;
+                std::string value(line + strlen("Coefficient:") + 1);
+                std::vector<uint8_t> bin;
+                try {
+                    isc::util::encode::decodeBase64(value, bin);
+                } catch (const BadValue& exc) {
+                    RSA_free(rsa);
+                    fclose(fp);
+                    isc_throw(BadKey, "Coefficient: " << exc.what());
+                }
+                int len = static_cast<int>(bin.size());
+                rsa->iqmp = BN_bin2bn(&bin[0], len, NULL);
+            }
+        }
+        fclose(fp);
+        if (!got_algorithm) {
+            RSA_free(rsa);
+            isc_throw(BadKey, "Missing Algorithm entry");
+        }
+        if (!got_modulus) {
+            RSA_free(rsa);
+            isc_throw(BadKey, "Missing Modulus entry");
+        }
+        if (!got_pub_exponent) {
+            RSA_free(rsa);
+            isc_throw(BadKey, "Missing PublicExponent entry");
+        }
+        if (!got_priv_exponent) {
+            RSA_free(rsa);
+            isc_throw(BadKey, "Missing PrivateExponent entry");
+        }
+        if (!got_prime1) {
+            RSA_free(rsa);
+            isc_throw(BadKey, "Missing Prime1 entry");
+        }
+        if (!got_prime2) {
+            RSA_free(rsa);
+            isc_throw(BadKey, "Missing Prime2 entry");
+        }
+        if (!got_exponent1) {
+            RSA_free(rsa);
+            isc_throw(BadKey, "Missing Exponent1 entry");
+        }
+        if (!got_exponent2) {
+            RSA_free(rsa);
+            isc_throw(BadKey, "Missing Exponent2 entry");
+        }
+        if (!got_coefficient) {
+            RSA_free(rsa);
+            isc_throw(BadKey, "Missing Coefficient entry");
+        }
+        pkey_ = EVP_PKEY_new();
+        if (!pkey_) {
+            RSA_free(rsa);
+            throw std::bad_alloc();
+        }
+        if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
+            RSA_free(rsa);
+            EVP_PKEY_free(pkey_);
+            pkey_ = NULL;
+            isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
+        }
+        // set1 bumped the reference counter
+        RSA_free(rsa);
+    } else if ((kind_ == PUBLIC) && (key_format == BASIC)) {
+        // PKCS#1 PEM file
+        // warn when password not empty
+        FILE* fp = fopen(filename.c_str(), "r");
+        if (!fp) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        RSA* rsa = PEM_read_RSAPublicKey(fp, NULL, 0, NULL);
+        fclose(fp);
+        if (!rsa) {
+            isc_throw(BadKey, "PEM_read_RSAPublicKey");
+        }
+        pkey_ = EVP_PKEY_new();
+        if (!pkey_) {
+            RSA_free(rsa);
+            throw std::bad_alloc();
+        }
+        if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
+            RSA_free(rsa);
+            EVP_PKEY_free(pkey_);
+            pkey_ = NULL;
+            isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
+        }
+        // set1 bumped the reference counter
+        RSA_free(rsa);
+    } else if ((kind_ == PUBLIC) && (key_format == ASN1)) {
+        // SubjectPublicKeyInfo PEM file
+        // warn when password not empty
+        FILE* fp = fopen(filename.c_str(), "r");
+        if (!fp) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        char* pwd = NULL;
+        if (!password.empty()) {
+            pwd = const_cast<char*>(password.c_str());
+        }
+        pkey_ = PEM_read_PUBKEY(fp, NULL, 0, pwd);
+        fclose(fp);
+        if (!pkey_) {
+            isc_throw(BadKey, "PEM_read_PUBKEY");
+        }
+        if (pkey_->type != EVP_PKEY_RSA) {
+            EVP_PKEY_free(pkey_);
+            pkey_ = NULL;
+            isc_throw(BadKey, "not a RSA Public Key");
+        }
+    } else if ((kind_ == PUBLIC) && (key_format == DNS)) {
+        // bind9 .key file (RDATA)
+        // warn when password not empty
+        if ((hash_ != MD5) && (hash_ != SHA1) &&
+            (hash_ != SHA256) && (hash_ != SHA512)) {
+            isc_throw(UnsupportedAlgorithm,
+                      "Not compatible hash algorithm: " <<
+                      static_cast<int>(hash_));
+        }
+        FILE* fp = fopen(filename.c_str(), "r");
+        if (!fp) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        char line[4096];
+        bool found = false;
+        while (fgets(line, sizeof(line), fp)) {
+            if ((line[0] == '\0') || (line[0] == ';')) {
+                continue;
+            }
+            if (strstr(line, "DNSKEY") == NULL) {
+                continue;
+            }
+            found = true;
+            if (line[strlen(line) - 1] == '\n') {
+                line[strlen(line) - 1] = 0;
+            }
+            break;
+        }
+        fclose(fp);
+        if (!found) {
+            isc_throw(BadKey, "Can't find a DNSKEY");
+        }
+        const char b64[] =
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
+            "ghijklmnopqrstuvwxyz0123456789+/=";
+        size_t last = strlen(line) - 1;
+        while (strchr(b64, static_cast<int>(line[last])) != NULL) {
+            --last;
+        }
+        const std::string value(line + last + 1);
+        std::vector<uint8_t> bin;
+        try {
+            util::encode::decodeBase64(value, bin);
+        } catch (const BadValue& exc) {
+           isc_throw(BadKey, "Can't decode base64: " << exc.what());
+        }
+        size_t key_len = bin.size();
+        const uint8_t* p = &bin[0];
+        unsigned int e_bytes = *p++;
+        --key_len;
+        if (e_bytes == 0) {
+            if (key_len < 2) {
+                isc_throw(BadKey, "Bad RSA Public Key: short exponent length");
+            }
+            e_bytes = (*p++) << 8;
+            e_bytes += *p++;
+            key_len -= 2;
+        }
+        if (key_len < e_bytes) {
+            isc_throw(BadKey, "Bad RSA Public Key: short exponent");
+        }
+        if ((key_len - e_bytes) < 64) {
+            isc_throw(BadKey, "Bad RSA Public Key: too short: " <<
+                      (key_len - e_bytes) * 8);
+        }
+        if ((key_len - e_bytes) > 512) {
+            isc_throw(BadKey, "Bad RSA Public Key: too large: " <<
+                      (key_len - e_bytes) * 8);
+        }
+        RSA* rsa = RSA_new();
+        if (!rsa) {
+            throw std::bad_alloc();
+        }
+        rsa->e = BN_bin2bn(p, e_bytes, NULL);
+        p += e_bytes;
+        key_len -= e_bytes;
+        rsa->n = BN_bin2bn(p, key_len, NULL);
+        if (!rsa->e || !rsa->n) {
+            RSA_free(rsa);
+            throw std::bad_alloc();
+        }
+        pkey_ = EVP_PKEY_new();
+        if (!pkey_) {
+            RSA_free(rsa);
+            throw std::bad_alloc();
+        }
+        if (!EVP_PKEY_set1_RSA(pkey_, rsa)) {
+            RSA_free(rsa);
+            EVP_PKEY_free(pkey_);
+            pkey_ = NULL;
+            isc_throw(LibraryError, "EVP_PKEY_set1_RSA");
+        }
+        // set1 bumped the reference counter
+        RSA_free(rsa);
+    } else if (kind_ == PUBLIC) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Public Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((kind_ == CERT) && (key_format == ASN1)) {
+        // Public Key Certificate PEM file
+        // warn when password not empty
+        FILE* fp = fopen(filename.c_str(), "r");
+        if (!fp) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        x509_ = PEM_read_X509(fp, NULL, 0, NULL);
+        fclose(fp);
+        if (!x509_) {
+            isc_throw(BadKey, "PEM_read_X509");
+        }
+        int sig_nid = OBJ_obj2nid(x509_->sig_alg->algorithm);
+        if (hash_ == MD5) {
+            if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.4")) {
+                X509_free(x509_);
+                x509_ = NULL;
+                isc_throw(BadKey, "Require a RSA MD5 certificate");
+            }
+        } else if (hash_ == SHA1) {
+            if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.5")) {
+                X509_free(x509_);
+                x509_ = NULL;
+                isc_throw(BadKey, "Require a RSA SHA1 certificate");
+            }
+        } else if (hash_ == SHA224) {
+            if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.14")) {
+                X509_free(x509_);
+                x509_ = NULL;
+                isc_throw(BadKey, "Require a RSA SHA224 certificate");
+            }
+        } else if (hash_ == SHA256) {
+            if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.11")) {
+                X509_free(x509_);
+                x509_ = NULL;
+                isc_throw(BadKey, "Require a RSA SHA256 certificate");
+            }
+        } else if (hash_ == SHA384) {
+            if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.12")) {
+                X509_free(x509_);
+                x509_ = NULL;
+                isc_throw(BadKey, "Require a RSA SHA384 certificate");
+            }
+        } else if (hash_ == SHA512) {
+            if (sig_nid != OBJ_txt2nid("1.2.840.113549.1.1.13")) {
+                X509_free(x509_);
+                x509_ = NULL;
+                isc_throw(BadKey, "Require a RSA SHA512 certificate");
+            }
+        } else {
+            X509_free(x509_);
+            x509_ = NULL;
+            isc_throw(UnsupportedAlgorithm,
+                      "Bad hash algorithm for certificate: " <<
+                      static_cast<int>(hash_));
+        }
+        pkey_ = X509_get_pubkey(x509_);
+        if (!pkey_) {
+            X509_free(x509_);
+            x509_ = NULL;
+            isc_throw(BadKey, "X509_get_pubkey");
+        }
+        if (pkey_->type != EVP_PKEY_RSA) {
+            EVP_PKEY_free(pkey_);
+            pkey_ = NULL;
+            X509_free(x509_);
+            x509_ = NULL;
+            isc_throw(BadKey, "not a RSA Public Key");
+        }
+    } else if (kind_ == CERT) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown Public Key Certificate format: " <<
+                  static_cast<int>(key_format));
+    } else {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Key kind: " << static_cast<int>(kind_));
+    }
+    mdctx_.reset(new EVP_MD_CTX);
+    EVP_MD_CTX_init(mdctx_.get());
+
+    if (!EVP_DigestInit_ex(mdctx_.get(), md, NULL)) {
+        EVP_MD_CTX_cleanup(mdctx_.get());
+        EVP_PKEY_free(pkey_);
+        pkey_ =NULL;
+        isc_throw(LibraryError, "EVP_DigestInit_ex");
+    }
+}
+
+/// @brief Destructor
+RsaAsymImpl::~RsaAsymImpl() {
+    if (mdctx_) {
+        EVP_MD_CTX_cleanup(mdctx_.get());
+    }
+    if (pkey_) {
+        EVP_PKEY_free(pkey_);
+        pkey_ = NULL;
+    }
+    if (x509_) {
+        X509_free(x509_);
+        x509_ = NULL;
+    }
+}
+
+/// @brief Returns the AsymAlgorithm of the object
+AsymAlgorithm RsaAsymImpl::getAsymAlgorithm() const {
+    return (algo_);
+}
+
+/// @brief Returns the HashAlgorithm of the object
+HashAlgorithm RsaAsymImpl::getHashAlgorithm() const {
+    return (hash_);
+}
+
+/// @brief Returns the AsymKeyKind of the object
+AsymKeyKind RsaAsymImpl::getAsymKeyKind() const {
+    return (kind_);
+}
+
+/// @brief Returns the key size in bits
+size_t RsaAsymImpl::getKeySize() const {
+    return (static_cast<size_t>(EVP_PKEY_bits(pkey_)));
+}
+
+/// @brief Returns the output size of the signature
+size_t RsaAsymImpl::getSignatureLength(const AsymFormat sig_format) const {
+    switch (sig_format) {
+    case BASIC:
+    case ASN1:
+    case DNS:
+        // In all cases a big integer of the size of n
+        return (static_cast<size_t>(EVP_PKEY_size(pkey_)));
+    default:
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Signature format: " <<
+                  static_cast<int>(sig_format));
+    }
+}           
+
+/// @brief Add data to digest
+void RsaAsymImpl::update(const void* data, const size_t len) {
+    if (!EVP_DigestUpdate(mdctx_.get(), data, len)) {
+        isc_throw(LibraryError, "EVP_DigestUpdate");
+    }
+}
+
+/// @brief Calculate the final signature
+void RsaAsymImpl::sign(isc::util::OutputBuffer& result, size_t len,
+                      const AsymFormat sig_format) {
+    unsigned int size = getSignatureLength(sig_format);
+    ossl::SecBuf<unsigned char> sig(size);
+    if (!EVP_SignFinal(mdctx_.get(), &sig[0], &size, pkey_)) {
+        isc_throw(LibraryError, "EVP_SignFinal");
+    }
+    if (len > size) {
+        len = size;
+    }
+    result.writeData(&sig[0], len);
+}
+
+/// @brief Calculate the final signature
+void RsaAsymImpl::sign(void* result, size_t len, const AsymFormat sig_format) {
+    unsigned int size = getSignatureLength(sig_format);
+    ossl::SecBuf<unsigned char> sig(size);
+    if (!EVP_SignFinal(mdctx_.get(), &sig[0], &size, pkey_)) {
+        isc_throw(LibraryError, "EVP_SignFinal");
+    }
+    if (len > size) {
+        len = size;
+    }
+    std::memcpy(result, &sig[0], len);
+}
+
+/// @brief Calculate the final signature
+std::vector<uint8_t> RsaAsymImpl::sign(size_t len,
+                                      const AsymFormat sig_format) {
+    unsigned int size = getSignatureLength(sig_format);
+    ossl::SecBuf<unsigned char> sig(size);
+    if (!EVP_SignFinal(mdctx_.get(), &sig[0], &size, pkey_)) {
+        isc_throw(LibraryError, "EVP_SignFinal");
+    }
+    // resize to min(len, size)
+    sig.resize(len < size ? len : size);
+    return (std::vector<uint8_t>(sig.begin(), sig.end()));
+}  
+
+/// @brief Verify an existing signature
+bool RsaAsymImpl::verify(const void* sig, size_t len,
+                        const AsymFormat sig_format) {
+    size_t size = getSignatureLength(sig_format);
+    if (len != size) {
+        return false;
+    }
+    unsigned char* sigbuf =
+        reinterpret_cast<unsigned char*>(const_cast<void*>(sig));
+    unsigned int siglen = static_cast<unsigned int>(len);
+    int status = EVP_VerifyFinal(mdctx_.get(), sigbuf, siglen, pkey_);
+    switch (status) {
+    case 1:
+        return true;
+    case 0:
+        return false;
+    case -1:
+    default:
+        isc_throw(LibraryError, "EVP_VerifyFinal");
+    }
+}
+
+/// @brief Clear the crypto state and go back to the initial state
+void RsaAsymImpl::clear() {
+    if (mdctx_) {
+        EVP_MD_CTX_cleanup(mdctx_.get());
+    } else {
+        mdctx_.reset(new EVP_MD_CTX);
+    }
+    EVP_MD_CTX_init(mdctx_.get());
+    const EVP_MD* md = ossl::getHashAlgorithm(hash_);
+    if (md == 0) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown hash algorithm: " <<
+                  static_cast<int>(hash_));
+    }
+    if (!EVP_DigestInit_ex(mdctx_.get(), md, NULL)) {
+        EVP_MD_CTX_cleanup(mdctx_.get());
+        EVP_PKEY_free(pkey_);
+        pkey_ =NULL;
+        isc_throw(LibraryError, "EVP_DigestInit_ex");
+    }
+}
+
+/// @brief Export the key value (binary)
+std::vector<uint8_t>
+RsaAsymImpl::exportkey(const AsymKeyKind key_kind,
+                      const AsymFormat key_format) const {
+    if ((key_kind == PRIVATE) && (key_format == BASIC)) {
+        // PKCS#1 Private Key
+        if (kind_ != PRIVATE) {
+            isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
+        }
+        RSA* rsa = EVP_PKEY_get1_RSA(pkey_);
+        if (!rsa) {
+            isc_throw(LibraryError, "EVP_PKEY_get1_RSA");
+        }
+        int len = i2d_RSAPrivateKey(rsa, NULL);
+        if (len < 0) {
+            RSA_free(rsa);
+            isc_throw(LibraryError, "i2d_RSAPrivateKey 0");
+        }
+        std::vector<uint8_t> der(static_cast<size_t>(len));
+        unsigned char* p = &der[0];
+        len = i2d_RSAPrivateKey(rsa, &p);
+        RSA_free(rsa);
+        if (len != static_cast<int>(der.size())) {
+            isc_throw(LibraryError, "i2d_RSAPrivateKey");
+        }
+        return der;
+    } else if (key_kind == PRIVATE) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Private Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((key_kind == PUBLIC) && (key_format == BASIC)) {
+        // PKCS#1 Public Key
+        RSA* rsa = EVP_PKEY_get1_RSA(pkey_);
+        if (!rsa) {
+            isc_throw(LibraryError, "EVP_PKEY_get1_RSA");
+        }
+        int len = i2d_RSAPublicKey(rsa, NULL);
+        if (len < 0) {
+            RSA_free(rsa);
+            isc_throw(LibraryError, "i2d_RSAPublicKey 0");
+        }
+        std::vector<uint8_t> der(static_cast<size_t>(len));
+        unsigned char* p = &der[0];
+        len = i2d_RSAPublicKey(rsa, &p);
+        RSA_free(rsa);
+        if (len != static_cast<int>(der.size())) {
+            isc_throw(LibraryError, "i2d_RSAPublicKey");
+        }
+        return der;
+    } else if ((key_kind == PUBLIC) && (key_format == ASN1)) {
+        // SubjectPublicKeyInfo
+        RSA* rsa = EVP_PKEY_get1_RSA(pkey_);
+        if (!rsa) {
+            isc_throw(LibraryError, "EVP_PKEY_get1_RSA");
+        }
+        int len = i2d_RSA_PUBKEY(rsa, NULL);
+        if (len < 0) {
+            RSA_free(rsa);
+            isc_throw(LibraryError, "i2d_RSA_PUBKEY 0");
+        }
+        std::vector<uint8_t> der(static_cast<size_t>(len));
+        unsigned char* p = &der[0];
+        len = i2d_RSA_PUBKEY(rsa, &p);
+        RSA_free(rsa);
+        if (len != static_cast<int>(der.size())) {
+            isc_throw(LibraryError, "i2d_RSA_PUBKEY");
+        }
+        return der;
+    } else if ((key_kind == PUBLIC) && (key_format == DNS)) {
+        // RFC 3110 DNS wire format
+        RSA* rsa = EVP_PKEY_get1_RSA(pkey_);
+        if (!rsa) {
+            isc_throw(LibraryError, "EVP_PKEY_get1_RSA");
+        }
+        size_t e_bytes = BN_num_bytes(rsa->e);
+        size_t mod_bytes = BN_num_bytes(rsa->n);
+        size_t x_bytes = 1;
+        if (e_bytes >= 256) {
+            x_bytes += 2;
+        }
+        std::vector<uint8_t> rdata(x_bytes + e_bytes + mod_bytes);
+        if (e_bytes < 256) {
+            rdata[0] = e_bytes;
+        } else {
+            rdata[0] = 0;
+            rdata[1] = (e_bytes >> 8) & 0xff;
+            rdata[2] = e_bytes & 0xff;
+        }
+        BN_bn2bin(rsa->e, &rdata[x_bytes]);
+        BN_bn2bin(rsa->n, &rdata[x_bytes + e_bytes]);
+        RSA_free(rsa);
+        return rdata;
+    } else if (key_kind == PUBLIC) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Public Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((key_kind == CERT) && (key_format == ASN1)) {
+        // X.509 Public Key Certificate
+        if (kind_ != CERT) {
+            isc_throw(UnsupportedAlgorithm, "Have no Certificate");
+        }
+        int len = i2d_X509(x509_, NULL);
+        if (len < 0) {
+            isc_throw(LibraryError, "i2d_X509 0");
+        }
+        std::vector<uint8_t> ber(static_cast<size_t>(len));
+        unsigned char* p = &ber[0];
+        len = i2d_X509(x509_, &p);
+        if (len != static_cast<int>(ber.size())) {
+            isc_throw(LibraryError, "i2d_X509");
+        }
+        return ber;
+    } else if (key_kind == CERT) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown Certificate format: " <<
+                  static_cast<int>(key_format));
+    } else {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Key kind: " <<
+                  static_cast<int>(key_kind));
+    }
+}
+
+/// @brief Export the key value (file)
+void RsaAsymImpl::exportkey(const std::string& filename,
+                           const std::string& password,
+                           const AsymKeyKind key_kind,
+                           const AsymFormat key_format) const {
+    if ((key_kind == PRIVATE) && (key_format == ASN1)) {
+        // PKCS#8 Private Key PEM file
+        if (kind_ != PRIVATE) {
+            isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
+        }
+        char* pwd = NULL;
+        const EVP_CIPHER* enc = NULL;
+        if (!password.empty()) {
+            pwd = const_cast<char*>(password.c_str());
+            enc = EVP_des_ede3_cbc();
+            if (!enc) {
+                isc_throw(LibraryError, "EVP_des_ede3_cbc");
+            }
+        }
+        FILE* fp = fopen(filename.c_str(), "w");
+        if (!fp) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        if (!PEM_write_PKCS8PrivateKey(fp, pkey_, enc, pwd,
+                                       static_cast<int>(password.size()),
+                                       0, NULL)) {
+            fclose(fp);
+            isc_throw(LibraryError, "PEM_write_PKCS8PrivateKey");
+        }
+        fclose(fp);
+    } else if ((key_kind == PRIVATE) && (key_format == DNS)) {
+        //  bind9 .private file
+        if (kind_ != PRIVATE) {
+            isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
+        }
+        if ((hash_ != MD5) && (hash_ != SHA1) &&
+            (hash_ != SHA256) && (hash_ != SHA512)) {
+            isc_throw(UnsupportedAlgorithm,
+                      "Not compatible hash algorithm: " <<
+                      static_cast<int>(hash_));
+        }
+        FILE* fp = fopen(filename.c_str(), "w");
+        if (!fp) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        RSA* rsa = EVP_PKEY_get1_RSA(pkey_);
+        if (!rsa) {
+            fclose(fp);
+            isc_throw(LibraryError, "EVP_PKEY_get1_RSA");
+        }
+        fprintf(fp, "Private-key-format: v1.2\n");
+        if (hash_ == MD5) {
+            fprintf(fp, "Algorithm: 1 (RSA)\n");
+        } else if (hash_ == SHA1) {
+            fprintf(fp, "Algorithm: 5 (RSASHA1)\n");
+        } else if (hash_ == SHA256) {
+            fprintf(fp, "Algorithm: 8 (RSASHA256)\n");
+        } else if (hash_ == SHA512) {
+            fprintf(fp, "Algorithm: 10 (RSASHA512)\n");
+        }
+        std::vector<uint8_t> bin;
+        bin.resize(BN_num_bytes(rsa->n));
+        BN_bn2bin(rsa->n, &bin[0]);
+        fprintf(fp, "Modulus: %s\n",
+                util::encode::encodeBase64(bin).c_str());
+        bin.resize(BN_num_bytes(rsa->e));
+        BN_bn2bin(rsa->e, &bin[0]);
+        fprintf(fp, "PublicExponent: %s\n",
+                util::encode::encodeBase64(bin).c_str());
+        bin.resize(BN_num_bytes(rsa->d));
+        BN_bn2bin(rsa->d, &bin[0]);
+        fprintf(fp, "PrivateExponent: %s\n",
+                util::encode::encodeBase64(bin).c_str());
+        bin.resize(BN_num_bytes(rsa->p));
+        BN_bn2bin(rsa->p, &bin[0]);
+        fprintf(fp, "Prime1: %s\n",
+                util::encode::encodeBase64(bin).c_str());
+        bin.resize(BN_num_bytes(rsa->q));
+        BN_bn2bin(rsa->q, &bin[0]);
+        fprintf(fp, "Prime2: %s\n",
+                util::encode::encodeBase64(bin).c_str());
+        bin.resize(BN_num_bytes(rsa->dmp1));
+        BN_bn2bin(rsa->dmp1, &bin[0]);
+        fprintf(fp, "Exponent1: %s\n",
+                util::encode::encodeBase64(bin).c_str());
+        bin.resize(BN_num_bytes(rsa->dmq1));
+        BN_bn2bin(rsa->dmq1, &bin[0]);
+        fprintf(fp, "Exponent2: %s\n",
+                util::encode::encodeBase64(bin).c_str());
+        bin.resize(BN_num_bytes(rsa->iqmp));
+        BN_bn2bin(rsa->iqmp, &bin[0]);
+        fprintf(fp, "Coefficient: %s\n",
+                util::encode::encodeBase64(bin).c_str());
+        fclose(fp);
+        RSA_free(rsa);
+    } else if (key_kind == PRIVATE) {
+        if (kind_ != PRIVATE) {
+            isc_throw(UnsupportedAlgorithm, "Have no RSA Private Key");
+        }
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Private Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((key_kind == PUBLIC) && (key_format == BASIC)) {
+        // PKCS#1 PEM file
+        // warn when password not empty
+        FILE* fp = fopen(filename.c_str(), "w");
+        if (!fp) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        RSA* rsa = EVP_PKEY_get1_RSA(pkey_);
+        if (!rsa) {
+            fclose(fp);
+            isc_throw(LibraryError, "EVP_PKEY_get1_RSA");
+        }
+        if (!PEM_write_RSAPublicKey(fp, rsa)) {
+            fclose(fp);
+            RSA_free(rsa);
+            isc_throw(LibraryError, "PEM_write_RSAPublicKey");
+        }
+        fclose(fp);
+        RSA_free(rsa);
+    } else if ((key_kind == PUBLIC) && (key_format == ASN1)) {
+        // SubjectPublicKeyInfo PEM file
+        // warn when password not empty
+        FILE* fp = fopen(filename.c_str(), "w");
+        if (!fp) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        if (!PEM_write_PUBKEY(fp, pkey_)) {
+            fclose(fp);
+            isc_throw(LibraryError, "PEM_write_PUBKEY");
+        }
+        fclose(fp);
+    }  else if ((key_kind == PUBLIC) && (key_format == DNS)) {
+        // bind9 .key file (RDATA)
+        // warn when password not empty
+        std::vector<uint8_t> bin = exportkey(key_kind, key_format);
+        FILE* fp = fopen(filename.c_str(), "w");
+        if (!fp) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        fprintf(fp, "; DNSKEY RDATA: %s\n",
+                util::encode::encodeBase64(bin).c_str());
+        fclose(fp);
+    } else if (key_kind == PUBLIC) {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Public Key format: " <<
+                  static_cast<int>(key_format));
+    } else if ((key_kind == CERT) && (key_format == ASN1)) {
+        // Public Key Certificate PEM file
+        // warn when password not empty
+        if (!x509_) {
+            isc_throw(UnsupportedAlgorithm, "Have no Certificate");
+        }
+        FILE* fp = fopen(filename.c_str(), "w");
+        if (!fp) {
+            isc_throw(BadKey, "Can't open file: " << filename);
+        }
+        if (!PEM_write_X509(fp, x509_)) {
+            fclose(fp);
+            isc_throw(LibraryError, "PEM_write_X509");
+        }
+        fclose(fp);
+    } else if (key_kind == CERT) {
+        if (!x509_) {
+            isc_throw(UnsupportedAlgorithm, "Have no Certificate");
+        }
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown Certificate format: " <<
+                  static_cast<int>(key_format));
+    } else {
+        isc_throw(UnsupportedAlgorithm,
+                  "Unknown RSA Key kind: " <<
+                  static_cast<int>(key_kind));
+    }
+}
+
+/// @brief Check the validity
+bool RsaAsymImpl::validate() const {
+    RSA* rsa;
+    X509_STORE* store;
+    X509_STORE_CTX* ctx;
+    int status;
+    switch (kind_) {
+    case PUBLIC:
+        // what to do?
+        return true;
+    case PRIVATE:
+        rsa = EVP_PKEY_get1_RSA(pkey_);
+        if (!rsa) {
+            return false;
+        }
+        status = RSA_check_key(rsa);
+        RSA_free(rsa);
+        return (status == 1);
+    case CERT:
+        store = X509_STORE_new();
+        if (!store) {
+            return false;
+        }
+        if (!X509_STORE_add_cert(store, x509_)) {
+            X509_STORE_free(store);
+            store = NULL;
+            return false;
+        }
+        ctx = X509_STORE_CTX_new();
+        if (!ctx) {
+            X509_STORE_free(store);
+            store = NULL;
+            return false;
+        }
+        if (!X509_STORE_CTX_init(ctx, store, x509_, NULL)) {
+            X509_STORE_CTX_free(ctx);
+            ctx = NULL;
+            X509_STORE_free(store);
+            store = NULL;
+            return false;
+        }
+        // By default OpenSSL skips self-signatures
+        X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CHECK_SS_SIGNATURE);
+        status = X509_verify_cert(ctx);
+        // text version of status available by
+        // X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx))
+        X509_STORE_CTX_free(ctx);
+        ctx = NULL;
+        X509_STORE_free(store);
+        store = NULL;
+        if (status == 1) {
+            return true;
+        }
+        return false;
+    default:
+        return false;
+    }
+}
+
+/// @brief Compare two keys
+bool RsaAsymImpl::compare(const RsaAsymImpl* other,
+                         const AsymKeyKind key_kind) const {
+    if (!other || (other->algo_ != RSA_)) {
+        return false;
+    }
+    int status;
+    switch (key_kind) {
+    case CERT:
+        // Special case for cert - cert
+        if ((kind_ == CERT) && (other->kind_ == CERT)) {
+            return (X509_cmp(x509_, other->x509_) == 0);
+        }
+        // At least one should be a cert
+        if ((kind_ != CERT) && (other->kind_ != CERT)) {
+            return false;
+        }
+        // For all other cases just compare public keys
+        // Falls into
+    case PUBLIC:
+        if ((kind_ != PUBLIC) &&
+            (kind_ != PRIVATE) &&
+            (kind_ != CERT)) {
+            return false;
+        }
+        if ((other->kind_ != PUBLIC) &&
+            (other->kind_ != PRIVATE) &&
+            (other->kind_ != CERT)) {
+            return false;
+        }
+        status = EVP_PKEY_cmp(pkey_, other->pkey_);
+        switch (status) {
+        case 1:
+            // match
+            return true;
+        case 0:
+            // don't match
+            return false;
+        case -1:
+            // different types
+            return false;
+        case -2:
+            // not supported
+            return false;
+        }
+        return false;
+    case PRIVATE:
+        if ((kind_ != PRIVATE) || (other->kind_ != PRIVATE)) {
+            return false;
+        }
+        // If public keys match so private too
+        status = EVP_PKEY_cmp(pkey_, other->pkey_);
+        switch (status) {
+        case 1:
+            // match
+            return true;
+        case 0:
+            // don't match
+            return false;
+        case -1:
+            // different types
+            return false;
+        case -2:
+            // not supported
+            return false;
+        }
+        return false;
+    default:
+        return false;
+    }
+}
+
+} // namespace cryptolink
+} // namespace isc
diff --git a/src/lib/cryptolink/openssl_rsa.h b/src/lib/cryptolink/openssl_rsa.h
new file mode 100644 (file)
index 0000000..9b675e0
--- /dev/null
@@ -0,0 +1,148 @@
+// Copyright (C) 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+namespace isc {
+namespace cryptolink {
+
+/// @brief OpenSSL implementation of asymmetrical cryptography (Asym).
+// Each method is the counterpart of the Asym corresponding method.
+class RsaAsymImpl : public AsymImpl {
+public:
+    /// @brief Constructor from a key, asym and hash algorithm,
+    ///        key kind and key binary format
+    ///
+    /// See constructor of the @ref isc::cryptolink::Asym class for details.
+    ///
+    /// @param key            The key to sign/verify with
+    /// @param len            The length of the key
+    /// @param hash_algorithm The hash algorithm
+    /// @param key_kind       The key kind
+    /// @param key_format     The key binary format
+    RsaAsymImpl(const void* key, size_t key_len,
+                const HashAlgorithm hash_algorithm,
+                const AsymKeyKind key_kind,
+                const AsymFormat key_format);
+
+    /// @brief Constructor from a key file with password,
+    ///        asym and hash algorithm, key kind and key binary format
+    ///
+    /// See constructor of the @ref isc::cryptolink::Asym class for details.
+    ///
+    /// @param filename       The key file name/path
+    /// @param password       The PKCS#8 password
+    /// @param hash_algorithm The hash algorithm
+    /// @param key_kind       The key kind
+    /// @param key_format     The key binary format
+    RsaAsymImpl(const std::string& filename,
+                const std::string& password,
+                const HashAlgorithm hash_algorithm,
+                const AsymKeyKind key_kind,
+                const AsymFormat key_format);
+
+    /// @brief Destructor
+    virtual ~RsaAsymImpl();
+
+    /// @brief Returns the AsymAlgorithm of the object
+    AsymAlgorithm getAsymAlgorithm() const;
+
+    /// @brief Returns the HashAlgorithm of the object
+    HashAlgorithm getHashAlgorithm() const;
+
+    /// @brief Returns the AsymKeyKind of the object
+    AsymKeyKind getAsymKeyKind() const;
+
+    /// @brief Returns the key size in bits
+    ///
+    size_t getKeySize() const;
+
+    /// @brief Returns the output size of the signature
+    ///
+    /// \param sig_format The signature binary format
+    size_t getSignatureLength(const AsymFormat sig_format) const;
+
+    /// @brief Add data to digest
+    ///
+    /// See @ref isc::cryptolink::AsymBase::update() for details.
+    void update(const void* data, const size_t len);
+
+    /// @brief Calculate the final signature
+    ///
+    /// See @ref isc::cryptolink::AsymBase::sign() for details.
+    void sign(isc::util::OutputBuffer& result, size_t len,
+              const AsymFormat sig_format);
+
+    /// @brief Calculate the final signature
+    ///
+    /// See @ref isc::cryptolink::AsymBase::sign() for details.
+    void sign(void* result, size_t len, const AsymFormat sig_format);
+
+    /// @brief Calculate the final signature
+    ///
+    /// See @ref isc::cryptolink::AsymBase::sign() for details.
+    std::vector<uint8_t> sign(size_t len, const AsymFormat sig_format);
+
+    /// @brief Verify an existing signature
+    ///
+    /// See @ref isc::cryptolink::AsymBase::verify() for details.
+    bool verify(const void* sig, size_t len, const AsymFormat sig_format);
+
+    /// @brief Clear the crypto state and go back to the initial state
+    /// (must be called before reusing an Asym object)
+    void clear();
+
+    /// @brief Export the key value (binary)
+    ///
+    /// See @ref isc::cryptolink::AsymBase::exportkey() for details
+    std::vector<uint8_t> exportkey(const AsymKeyKind key_kind,
+                                   const AsymFormat key_format) const;
+
+    /// @brief Export the key value (file)
+    ///
+    /// See @ref isc::cryptolink::AsymBase::exportkey() for details
+    void exportkey(const std::string& filename,
+                   const std::string& password,
+                   const AsymKeyKind key_kind,
+                   const AsymFormat key_format) const;
+
+    /// @brief Check the validity
+    ///
+    /// See @ref isc::cryptolink::AsymBase::validate() for details
+    bool validate() const;
+
+    /// @brief Compare two keys
+    ///
+    /// See @ref isc::cryptolink::Asym::compare() for details
+    bool compare(const RsaAsymImpl* other, const AsymKeyKind key_kind) const;
+
+private:
+    /// @brief The asymmetrical cryptography algorithm
+    AsymAlgorithm algo_;
+    /// @brief The hash algorithm
+    HashAlgorithm hash_;
+    /// @brief The key kind
+    AsymKeyKind kind_;
+    /// @brief The protected pointer to the OpenSSL EVP_MD_CTX structure
+    boost::scoped_ptr<EVP_MD_CTX> mdctx_;
+    /// @brief The raw pointer to the OpenSSL EVP_PKEY structure
+    /// There is no EVP_PKEY_init() or EVP_PKEY_cleanup() so
+    /// a smart pointer cannot be used.
+    EVP_PKEY* pkey_;
+    /// @brief The raw pointer to the OpenSSL X509 structure
+    /// There is no X509_init() or X509_cleanup() so
+    /// a smart pointer cannot be used.
+    X509* x509_;
+};
+
+} // namespace cryptolink
+} // namespace isc