1111#include < cassert>
1212#include < format>
1313#include < fstream>
14+ #include < gsl/gsl>
1415#include < iomanip>
16+ #include < memory>
1517#include < ranges>
1618#include < stdexcept>
1719#include < string>
@@ -35,53 +37,65 @@ std::string Auth::signPayload(const std::string &payload) {
3537}
3638
3739std::vector<unsigned char > Auth::getSeedFromPem () const {
38- FILE *fp = fopen (privatePemPath_.c_str (), " r" );
39- if (fp == nullptr ) {
40+ // fopen is unsafe, wrap in RAII
41+ const auto fileCloser = [](gsl::owner<FILE *> fp) {
42+ if (fp) fclose (fp);
43+ };
44+ std::unique_ptr<FILE, decltype (fileCloser)> fp (fopen (privatePemPath_.c_str (), " r" ),
45+ fileCloser);
46+ if (!fp) {
4047 throw std::runtime_error (" Failed to open PEM file" );
4148 }
42- EVP_PKEY *pkey = PEM_read_PrivateKey (fp, nullptr , nullptr , nullptr );
43- fclose (fp);
44- if (pkey == nullptr ) {
49+
50+ // PEM_read_PrivateKey is unsafe, wrap in RAII
51+ const auto keyCloser = [](EVP_PKEY *pkey) {
52+ if (pkey) EVP_PKEY_free (pkey);
53+ };
54+ std::unique_ptr<EVP_PKEY, decltype (keyCloser)> pkey (
55+ PEM_read_PrivateKey (fp.get (), nullptr , nullptr , nullptr ), keyCloser);
56+ if (!pkey) {
4557 throw std::runtime_error (" Failed to read private key from PEM" );
4658 }
4759
48- size_t len = 32 ; // Ed25519 private key seed size
49- std::vector<unsigned char > seed (len);
50- if (EVP_PKEY_get_raw_private_key (pkey, seed.data (), &len) != 1 ) {
60+ constexpr size_t ED25519_SEED_SIZE = 32 ;
61+ size_t len = ED25519_SEED_SIZE;
62+ std::vector<unsigned char > seed (ED25519_SEED_SIZE);
63+ if (EVP_PKEY_get_raw_private_key (pkey.get (), seed.data (), &len) != 1 ) {
5164 throw std::runtime_error (" Failed to get raw private key" );
5265 }
53- if (len != 32 ) {
54- throw std::runtime_error (" Unexpected private key length" );
66+ if (len != ED25519_SEED_SIZE) {
67+ throw std::runtime_error (
68+ std::format (" Unexpected private key length, length [{}]" , len));
5569 }
5670
57- EVP_PKEY_free (pkey);
5871 return seed;
5972}
6073
6174// static
6275std::string Auth::signPayload (const std::string &payload,
6376 const std::vector<unsigned char > &seed) {
64- unsigned char pk[ crypto_sign_PUBLICKEYBYTES] ;
65- unsigned char sk[ crypto_sign_SECRETKEYBYTES] ; // 64 bytes
77+ std::array< unsigned char , crypto_sign_PUBLICKEYBYTES> pk{} ;
78+ std::array< unsigned char , crypto_sign_SECRETKEYBYTES> sk{} ; // 64 bytes
6679
6780 // Generate keypair from seed
68- if (crypto_sign_seed_keypair (pk, sk, seed.data ()) != 0 ) {
81+ if (crypto_sign_seed_keypair (pk. data () , sk. data () , seed.data ()) != 0 ) {
6982 throw std::runtime_error (" Failed to generate keypair from seed" );
7083 }
7184
72- unsigned char sig[ crypto_sign_BYTES] ;
73- if (crypto_sign_detached (sig, nullptr ,
85+ std::array< unsigned char , crypto_sign_BYTES> sig{} ;
86+ if (crypto_sign_detached (sig. data () , nullptr ,
7487 reinterpret_cast <const unsigned char *>(payload.data ()),
75- payload.size (), sk) != 0 ) {
88+ payload.size (), sk. data () ) != 0 ) {
7689 throw std::runtime_error (" Failed to sign payload" );
7790 }
7891
7992 // Base64 encode signature
80- char b64[crypto_sign_BYTES * 2 ];
81- sodium_bin2base64 (b64, sizeof (b64), sig, sizeof (sig),
93+
94+ std::array<char , crypto_sign_BYTES * 2 > b64{};
95+ sodium_bin2base64 (b64.data (), sizeof (b64), sig.data (), sizeof (sig),
8296 sodium_base64_VARIANT_ORIGINAL_NO_PADDING);
8397
84- return b64;
98+ return b64. data () ;
8599}
86100
87101void Auth::clearKeys () {
0 commit comments