diff --git a/include/opendht/crypto.h b/include/opendht/crypto.h
index 3514ba75badc9d20ea41c6372c94a3117baefa36..9bba9ffd82a7ee8814eab5f425baf790ced85a93 100644
--- a/include/opendht/crypto.h
+++ b/include/opendht/crypto.h
@@ -308,6 +308,8 @@ struct OPENDHT_PUBLIC Certificate {
      */
     std::string toString(bool chain = true) const;
 
+    std::string print() const;
+
     static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", Identity ca = {}, bool is_ca = false);
 
     gnutls_x509_crt_t cert {};
@@ -320,14 +322,24 @@ private:
 
 class OPENDHT_PUBLIC RevocationList
 {
+    using clock = std::chrono::system_clock;
+    using time_point = clock::time_point;
 public:
     RevocationList();
     RevocationList(const Blob& b);
     ~RevocationList();
 
+    void pack(Blob& b) const;
+    void unpack(const uint8_t* dat, size_t dat_size);
+    Blob getPacked() const {
+        Blob b;
+        pack(b);
+        return b;
+    }
+
     bool isRevoked(const Certificate& crt) const;
 
-    void revoke(const Certificate& crt, std::chrono::system_clock::time_point t = {});
+    void revoke(const Certificate& crt, time_point t = time_point::min());
 
     /**
      * Sign this revocation list using provided key and certificate.
@@ -335,11 +347,9 @@ public:
     void sign(const PrivateKey&, const Certificate&);
     void sign(const Identity& id) { sign(*id.first, *id.second); }
 
-    bool isIssuedBy(const Certificate& crt);
-
-    bool isValid(const Certificate& issuer);
+    bool isSignedBy(const Certificate& issuer) const;
 
-    std::string toString();
+    std::string toString() const;
 
     gnutls_x509_crl_t get() { return crl; }
 
diff --git a/src/crypto.cpp b/src/crypto.cpp
index f34849a44796a2f3b37ae873293cc9c273ec77ea..4a3c13c6debf99859a9c0e56ba313b6d882322df 100644
--- a/src/crypto.cpp
+++ b/src/crypto.cpp
@@ -725,6 +725,16 @@ Certificate::toString(bool chain) const
     return ss.str();
 }
 
+std::string
+Certificate::print() const
+{
+    gnutls_datum_t out;
+    gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &out);
+    std::string ret(out.data, out.data+out.size);
+    gnutls_free(out.data);
+    return ret;
+}
+
 PrivateKey
 PrivateKey::generate(unsigned key_length)
 {
@@ -834,14 +844,13 @@ RevocationList::RevocationList()
 RevocationList::RevocationList(const Blob& b)
 {
     gnutls_x509_crl_init(&crl);
-    const gnutls_datum_t gdat {(uint8_t*)b.data(), (unsigned)b.size()};
-    if (auto err_pem = gnutls_x509_crl_import(crl, &gdat, GNUTLS_X509_FMT_PEM))
-        if (auto err_der = gnutls_x509_crl_import(crl, &gdat, GNUTLS_X509_FMT_DER)) {
-            gnutls_x509_crl_deinit(crl);
-            crl = nullptr;
-            throw CryptoException(std::string("Can't load CRL: PEM: ") + gnutls_strerror(err_pem)
-                                                           + " DER: "  + gnutls_strerror(err_der));
-        }
+    try {
+        unpack(b.data(), b.size());
+    } catch (const std::exception& e) {
+        gnutls_x509_crl_deinit(crl);
+        crl = nullptr;
+        throw e;
+    }
 }
 
 RevocationList::~RevocationList()
@@ -852,6 +861,29 @@ RevocationList::~RevocationList()
     }
 }
 
+void
+RevocationList::pack(Blob& b) const
+{
+    gnutls_datum_t gdat {nullptr, 0};
+    if (auto err = gnutls_x509_crl_export2(crl, GNUTLS_X509_FMT_PEM, &gdat)) {
+        throw CryptoException(std::string("Can't export CRL: ") + gnutls_strerror(err));
+    }
+    b.insert(b.end(), gdat.data, gdat.data + gdat.size);
+}
+
+void
+RevocationList::unpack(const uint8_t* dat, size_t dat_size)
+{
+    if (std::numeric_limits<unsigned>::max() < dat_size)
+        throw CryptoException("Can't load CRL: too large!");
+    const gnutls_datum_t gdat {(uint8_t*)dat, (unsigned)dat_size};
+    if (auto err_pem = gnutls_x509_crl_import(crl, &gdat, GNUTLS_X509_FMT_PEM))
+        if (auto err_der = gnutls_x509_crl_import(crl, &gdat, GNUTLS_X509_FMT_DER)) {
+            throw CryptoException(std::string("Can't load CRL: PEM: ") + gnutls_strerror(err_pem)
+                                                           + " DER: "  + gnutls_strerror(err_der));
+        }
+}
+
 bool
 RevocationList::isRevoked(const Certificate& crt) const
 {
@@ -864,6 +896,8 @@ RevocationList::isRevoked(const Certificate& crt) const
 void
 RevocationList::revoke(const Certificate& crt, std::chrono::system_clock::time_point t)
 {
+    if (t == time_point::min())
+        t = clock::now();
     if (auto err = gnutls_x509_crl_set_crt(crl, crt.cert, std::chrono::system_clock::to_time_t(t)))
         throw CryptoException(std::string("Can't revoke certificate: ") + gnutls_strerror(err));
 }
@@ -875,7 +909,7 @@ enum class Endian : uint32_t
 };
 
 template <typename T>
-T endian(T w, Endian endian)
+T endian(T w, Endian endian = Endian::BIG)
 {
     // this gets optimized out into if (endian == host_endian) return w;
     union { uint64_t quad; uint32_t islittle; } t;
@@ -908,9 +942,11 @@ RevocationList::sign(const PrivateKey& key, const Certificate& ca)
     size_t number_sz {sizeof(number)};
     unsigned critical {0};
     gnutls_x509_crl_get_number(crl, &number, &number_sz, &critical);
-    auto s = endian(number, Endian::BIG);
-    s++;
-    number = endian(s, Endian::BIG);
+    if (number == 0) {
+        number = (uint64_t)1 | ((uint64_t)1 << (7*8));
+        number_sz = sizeof(number);
+    }
+    number = endian(endian(number) + 1);
     if (auto err = gnutls_x509_crl_set_number(crl, &number, sizeof(number)))
         throw CryptoException(std::string("Can't set CRL update time: ") + gnutls_strerror(err));   
     if (auto err = gnutls_x509_crl_sign2(crl, ca.cert, key.x509_key, GNUTLS_DIG_SHA512, 0))
@@ -918,20 +954,19 @@ RevocationList::sign(const PrivateKey& key, const Certificate& ca)
 }
 
 bool
-RevocationList::isIssuedBy(const Certificate& crt)
-{
-    return gnutls_x509_crl_check_issuer(crl, crt.cert);
-}
-
-bool
-RevocationList::isValid(const Certificate& issuer)
+RevocationList::isSignedBy(const Certificate& issuer) const
 {
     unsigned result {0};
-    gnutls_x509_crl_verify(crl, &issuer.cert, 1, 0, &result);
+    auto err = gnutls_x509_crl_verify(crl, &issuer.cert, 1, 0, &result);
+    if (err < 0) {
+        //std::cout << "Can't verify CRL: " << err << " " << result << " " << gnutls_strerror(err) << std::endl;
+        return false;
+    }
+    return result == 0;
 }
 
 std::string
-RevocationList::toString()
+RevocationList::toString() const
 {
     gnutls_datum_t out;
     gnutls_x509_crl_print(crl, GNUTLS_CRT_PRINT_FULL, &out);