Generating certificates with C++ and OpenSSL API
I’ve been reading about core infrastructure components in the major technology companies and I noticed that C++ is quite common in this area and I decided to invest more time learning and practcing C++. I’ve been following the development and evolution of modern C++ and I really like it even with the push of RiiR and RiiG nowadays.
The problem I’ve chosen to play is the certificate generation and management for microservices using mTLS and the goal is to create a service that exports a gRPC interface that will respond to a few methods to generate, validate and revoke certificates and will also produce CSR requests to integrate with external CA authorities.
In this exercise the focus was to learn the OpenSSL C API and also practice C++ development using modern features.
The use of OpenSSL API in this project is relatively simple but made use of a few areas of the API such as
BIO_ functions to handle memory buffer,
PEM_ to read keys and generate X509 certificates in this format,
RSA_ is used to generate private and public keys as well as sign certificates with the CA public key and
X509_ functions to handle the certificate signature.
With C++ and modern features what I really mean is
auto and they are all simple and yet pretty convinient additions to the language that I enjoyed using.
unique_ptr is a smart pointer and was really useful to work with components from the OpenSSL API that required initialization and destruction of resources,
decltype was used to declare alias to the
unique_ptr types of the resources and
auto to deduce the return of
std::make_unique to create smart pointer from primitive types.
auto is probably the most known new feature since C++11 and use used to deduce the type of variables and function returns as well as arguments and declared types.
// Instead of BIO_s_mem(), use BIO, BIO_free unique ptr allow // BIO_ptr.get() to get a reference and will free when out of scope. using BIO_ptr = std::unique_ptr<BIO, decltype(&BIO_free)>; BIO_ptr bio(BIO_new(BIO_s_mem()), BIO_free); // auto instead of std::unique_ptr<char>(size_) &, no need to free // size could be dynamic. auto cert = std::make_unique<char>(this->default_buf_size_);
Working on this project for fun has been an interesting experience, even though I like C and C++ I’m aware of the weekenesses and the pain of dependency managemnet and the build ecosystem, it is clear why Go and Rust are better choices for anything new being develobed by a team intended to be a maintanable project.
I’m looking forward to playing even more with modern C++ features and I intend to continue learning and evolving this project to something useful at least to my needs.
Lets not forget the pain that is to manage dependencies in C++ specially when multi platform is involved and if you manage depedencies using the OS package manager it is even worst since reproducible builds becomes impossible. I don’t have experience with any other dependency management for C++ and I’ve tried
vcpkg on Windows and its impressive, would be nice if it the project was multi-platform too.
First, OpenSSL is terrible and it is understanable that it should be boring so true that google called their implementation BoringSSL.
Was fun learning the internals of OpenSSL and was interesting finding out that it is and it should be boring, the API is relatively simple but the fun part was learning about the concepts around certificates, keys and binary I/O.
Oh and here the project that of course is always WIP: https://github.com/rsampaio/pkiSvc