7

I use some using statements and unique_ptr to work with OpenSSL, as suggested in another question. Without, code becomes really ugly and I am not so much a fan of goto statements.

So far I have changed my code as far as possible. Here are examples, what I use:

using BIO_ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>;
using X509_ptr = std::unique_ptr<X509, decltype(&::X509_free)>;
using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
using PKCS7_ptr = std::unique_ptr<PKCS7, decltype(&::PKCS7_free)>;
...

BIO_ptr tbio(BIO_new_file(some_filename, "r"), ::BIO_free);

Now I have the need of a STACK_OF(X509) and I do not know, if this is also possible with unique_ptr. I am looking for something similar to below, but this is not working.

using STACK_OF_X509_ptr = std::unique_ptr<STACK_OF(X509), decltype(&::sk_X509_free)>;

I also tried the Functor:

struct StackX509Deleter {
    void operator()(STACK_OF(X509) *ptr) {
        sk_X509_free(ptr);
    }
};

using STACK_OF_X509_ptr = std::unique_ptr<STACK_OF(X509), StackX509Deleter>;

STACK_OF_X509_ptr chain(loadIntermediate(cert.string()));

The compiler accepts this and the application runs. Just one question: In other unique_ptrs as shown above, I always had specified a second argument, so I bet I am missing something:

STACK_OF_X509_ptr chain(loadIntermediate(cert.string()),  ??????);

How do I use C++ unique_ptr and OpenSSL's STACK_OF(X509)*?

Community
  • 1
  • 1
Christian Rößner
  • 447
  • 1
  • 5
  • 18
  • 1
    Was there perhaps an error message? Maybe a compilable code snippet we could use to replicate? – wally Jul 01 '16 at 12:46
  • 2
    The Deleter you're providing doesn't conform to the required Deleter prototype. You need to write a custom deallocator (a functor) that acceps `unique_ptr::pointer` as argument and invokes `sk_X509_free` internally. Then you can use `std::unique_ptr;`. – jweyrich Jul 01 '16 at 12:49
  • @jweyrich, I think, I do understand it :-) A Functor is something like operator(), is it? Do I need to write a class for it with this operator defined? Do you have an example for me? Please :-) – Christian Rößner Jul 01 '16 at 12:53
  • Can this also be done with a lambda? – Christian Rößner Jul 01 '16 at 12:55
  • 1
    @ChristianRößner: Right. A function object (or functor) is a struct/class containing a method that overrides the `()` operator. For examples, see [IntComparator](https://en.wikipedia.org/wiki/Function_object#In_C_and_C.2B.2B) or [Accumulator](http://stackoverflow.com/a/317528/298054). – jweyrich Jul 01 '16 at 12:57
  • 1
    @ChristianRößner - First, visit [STACK API](http://wiki.openssl.org/index.php/STACK_API) on the OpenSSL wiki. Second, `STACK_OF` is a macro. I *believe* its type is `X509*`. You might try to use a `typedef` that gets to the underlying type. You also might using `DECLARE_STACK_OF`. (Sorry I don't have better for you. I have not used them like that before). – jww Jul 01 '16 at 14:34
  • I "think" I just got a solution. I will edit my original post – Christian Rößner Jul 01 '16 at 14:36
  • 1
    Well done @ChristianRößner! Pretty clean solution! Now you might post your solution as an answer to your own question and accept it! :-) – jweyrich Jul 01 '16 at 14:45

1 Answers1

8

I defined a regular function:

void stackOfX509Deleter(STACK_OF(X509) *ptr) {
    sk_X509_free(ptr);
}

Then I use it in my code:

using STACK_OF_X509_ptr = std::unique_ptr<STACK_OF(X509),
    decltype(&stackOfX509Deleter)>;

STACK_OF_X509_ptr chain(loadIntermediate(cert.string()),
                    stackOfX509Deleter);
Christian Rößner
  • 447
  • 1
  • 5
  • 18