Commit ac67b05d19037606a10e523836768afbcf1531ae

Authored by Jay Berkenbilt
1 parent 28a049a0

Make it actually possible to register a crypto impl

include/qpdf/QPDFCryptoProvider.hh
@@ -46,10 +46,21 @@ class QPDFCryptoProvider @@ -46,10 +46,21 @@ class QPDFCryptoProvider
46 QPDF_DLL 46 QPDF_DLL
47 static std::shared_ptr<QPDFCryptoImpl> getImpl(std::string const& name); 47 static std::shared_ptr<QPDFCryptoImpl> getImpl(std::string const& name);
48 48
  49 + typedef std::function<std::shared_ptr<QPDFCryptoImpl>()> provider_fn;
  50 +
  51 + // Register a crypto implementation with the given name. The provider function must return
  52 + // a shared pointer to an instance of the implementation class, which must be derived from
  53 + // QPDFCryptoImpl.
  54 + QPDF_DLL static void registerImpl(std::string const& name, provider_fn f);
  55 +
49 // Register the given type (T) as a crypto implementation. T must be derived from QPDFCryptoImpl 56 // Register the given type (T) as a crypto implementation. T must be derived from QPDFCryptoImpl
50 // and must have a constructor that takes no arguments. 57 // and must have a constructor that takes no arguments.
51 template <typename T> 58 template <typename T>
52 - QPDF_DLL static void registerImpl(std::string const& name); 59 + static void
  60 + registerImpl(std::string const& name)
  61 + {
  62 + registerImpl(name, std::make_shared<T>);
  63 + }
53 64
54 // Set the crypto provider registered with the given name as the default crypto implementation. 65 // Set the crypto provider registered with the given name as the default crypto implementation.
55 QPDF_DLL 66 QPDF_DLL
@@ -72,8 +83,7 @@ class QPDFCryptoProvider @@ -72,8 +83,7 @@ class QPDFCryptoProvider
72 static QPDFCryptoProvider& getInstance(); 83 static QPDFCryptoProvider& getInstance();
73 84
74 std::shared_ptr<QPDFCryptoImpl> getImpl_internal(std::string const& name) const; 85 std::shared_ptr<QPDFCryptoImpl> getImpl_internal(std::string const& name) const;
75 - template <typename T>  
76 - void registerImpl_internal(std::string const& name); 86 + void registerImpl_internal(std::string const& name, provider_fn f);
77 void setDefaultProvider_internal(std::string const& name); 87 void setDefaultProvider_internal(std::string const& name);
78 88
79 class Members 89 class Members
@@ -89,7 +99,6 @@ class QPDFCryptoProvider @@ -89,7 +99,6 @@ class QPDFCryptoProvider
89 Members(Members const&) = delete; 99 Members(Members const&) = delete;
90 Members& operator=(Members const&) = delete; 100 Members& operator=(Members const&) = delete;
91 101
92 - typedef std::function<std::shared_ptr<QPDFCryptoImpl>()> provider_fn;  
93 std::string default_provider; 102 std::string default_provider;
94 std::map<std::string, provider_fn> providers; 103 std::map<std::string, provider_fn> providers;
95 }; 104 };
libqpdf/QPDFCryptoProvider.cc
@@ -30,11 +30,10 @@ QPDFCryptoProvider::getImpl(std::string const&amp; name) @@ -30,11 +30,10 @@ QPDFCryptoProvider::getImpl(std::string const&amp; name)
30 return getInstance().getImpl_internal(name); 30 return getInstance().getImpl_internal(name);
31 } 31 }
32 32
33 -template <typename T>  
34 void 33 void
35 -QPDFCryptoProvider::registerImpl(std::string const& name) 34 +QPDFCryptoProvider::registerImpl(std::string const& name, provider_fn f)
36 { 35 {
37 - getInstance().registerImpl_internal<T>(name); 36 + getInstance().registerImpl_internal(name, std::move(f));
38 } 37 }
39 38
40 void 39 void
@@ -47,13 +46,13 @@ QPDFCryptoProvider::QPDFCryptoProvider() : @@ -47,13 +46,13 @@ QPDFCryptoProvider::QPDFCryptoProvider() :
47 m(std::make_shared<Members>()) 46 m(std::make_shared<Members>())
48 { 47 {
49 #ifdef USE_CRYPTO_NATIVE 48 #ifdef USE_CRYPTO_NATIVE
50 - registerImpl_internal<QPDFCrypto_native>("native"); 49 + registerImpl_internal("native", std::make_shared<QPDFCrypto_native>);
51 #endif 50 #endif
52 #ifdef USE_CRYPTO_GNUTLS 51 #ifdef USE_CRYPTO_GNUTLS
53 - registerImpl_internal<QPDFCrypto_gnutls>("gnutls"); 52 + registerImpl_internal("gnutls", std::make_shared<QPDFCrypto_gnutls>);
54 #endif 53 #endif
55 #ifdef USE_CRYPTO_OPENSSL 54 #ifdef USE_CRYPTO_OPENSSL
56 - registerImpl_internal<QPDFCrypto_openssl>("openssl"); 55 + registerImpl_internal("openssl", std::make_shared<QPDFCrypto_openssl>);
57 #endif 56 #endif
58 std::string default_crypto; 57 std::string default_crypto;
59 if (!QUtil::get_env("QPDF_CRYPTO_PROVIDER", &default_crypto)) { 58 if (!QUtil::get_env("QPDF_CRYPTO_PROVIDER", &default_crypto)) {
@@ -80,11 +79,10 @@ QPDFCryptoProvider::getImpl_internal(std::string const&amp; name) const @@ -80,11 +79,10 @@ QPDFCryptoProvider::getImpl_internal(std::string const&amp; name) const
80 return m->providers[name](); 79 return m->providers[name]();
81 } 80 }
82 81
83 -template <typename T>  
84 void 82 void
85 -QPDFCryptoProvider::registerImpl_internal(std::string const& name) 83 +QPDFCryptoProvider::registerImpl_internal(std::string const& name, provider_fn f)
86 { 84 {
87 - m->providers[name] = std::make_shared<T>; 85 + m->providers[name] = std::move(f);
88 } 86 }
89 87
90 void 88 void
libtests/CMakeLists.txt
@@ -8,6 +8,7 @@ set(TEST_PROGRAMS @@ -8,6 +8,7 @@ set(TEST_PROGRAMS
8 buffer 8 buffer
9 closed_file_input_source 9 closed_file_input_source
10 concatenate 10 concatenate
  11 + crypto_provider
11 dct_compress 12 dct_compress
12 dct_uncompress 13 dct_uncompress
13 flate 14 flate
libtests/crypto_provider.cc 0 → 100644
  1 +#include <qpdf/assert_test.h>
  2 +
  3 +#include <qpdf/MD5.hh>
  4 +#include <qpdf/QPDFCryptoImpl.hh>
  5 +#include <qpdf/QPDFCryptoProvider.hh>
  6 +#include <cstring>
  7 +#include <iostream>
  8 +
  9 +// This is a dummy crypto implementation that only implements MD5 digest. It doesn't work, but
  10 +// it enables us to exercise the wiring of registering, querying, and setting a crypto provider.
  11 +class Potato: public QPDFCryptoImpl
  12 +{
  13 + public:
  14 + void
  15 + provideRandomData(unsigned char* data, size_t len) override
  16 + {
  17 + }
  18 + void
  19 + MD5_init() override
  20 + {
  21 + }
  22 + void
  23 + MD5_update(const unsigned char* data, size_t len) override
  24 + {
  25 + }
  26 + void
  27 + MD5_finalize() override
  28 + {
  29 + }
  30 + void
  31 + MD5_digest(unsigned char* digest) override
  32 + {
  33 + std::memcpy(digest, "0123456789abcdef", sizeof(QPDFCryptoImpl::MD5_Digest));
  34 + }
  35 + void
  36 + SHA2_init(int bits) override
  37 + {
  38 + }
  39 + void
  40 + SHA2_update(const unsigned char* data, size_t len) override
  41 + {
  42 + }
  43 + void
  44 + SHA2_finalize() override
  45 + {
  46 + }
  47 + std::string
  48 + SHA2_digest() override
  49 + {
  50 + return std::string();
  51 + }
  52 + void
  53 + RC4_init(const unsigned char* key_data, int key_len) override
  54 + {
  55 + }
  56 + void
  57 + RC4_process(const unsigned char* in_data, size_t len, unsigned char* out_data) override
  58 + {
  59 + }
  60 + void
  61 + RC4_finalize() override
  62 + {
  63 + }
  64 + void
  65 + rijndael_init(
  66 + bool encrypt,
  67 + const unsigned char* key_data,
  68 + size_t key_len,
  69 + bool cbc_mode,
  70 + unsigned char* cbc_block) override
  71 + {
  72 + }
  73 + void
  74 + rijndael_process(unsigned char* in_data, unsigned char* out_data) override
  75 + {
  76 + }
  77 + void
  78 + rijndael_finalize() override
  79 + {
  80 + }
  81 +};
  82 +
  83 +int
  84 +main()
  85 +{
  86 + auto initial = QPDFCryptoProvider::getDefaultProvider();
  87 + QPDFCryptoProvider::registerImpl<Potato>("potato");
  88 + QPDFCryptoProvider::setDefaultProvider("potato");
  89 + assert(QPDFCryptoProvider::getDefaultProvider() == "potato");
  90 + MD5 m;
  91 + m.encodeString("quack"); // anything
  92 + MD5::Digest d;
  93 + m.digest(d);
  94 + // hex for 0123456789abcdef
  95 + assert(m.unparse() == "30313233343536373839616263646566");
  96 + std::cout << "assertions passed\n";
  97 + return 0;
  98 +}
libtests/qtest/crypto_provider.test 0 → 100644
  1 +#!/usr/bin/env perl
  2 +require 5.008;
  3 +use warnings;
  4 +use strict;
  5 +
  6 +require TestDriver;
  7 +
  8 +my $td = new TestDriver('crypto_provider');
  9 +
  10 +$td->runtest("QINTC",
  11 + {$td->COMMAND => "crypto_provider"},
  12 + {$td->STRING => "assertions passed\n",
  13 + $td->EXIT_STATUS => 0},
  14 + $td->NORMALIZE_NEWLINES);
  15 +
  16 +$td->report(1);