Remove OpenSSL file BIO operations

Summary:
^
Change necessary when OpenSSL is compiled without STDIO for file operations. Basically, don't use the BIO file API's. Instead use in-memory BIO and do file operations manually.

UPDATE:

The changes were good, but have been simplified and fixed. A fixed was needed as to read and write the file in binary mode. This has no effect in POSIX systems but it does on Windows and this change was made for Windows. It meant that the BIO was incorrectly written to disk thus corrupting its content.

Changelog: Remove OpenSSL file BIO operations

Reviewed By: jknoxville

Differential Revision: D36060992

fbshipit-source-id: 21b30582dd0b32c24b8ba001d6993034d92de1da
This commit is contained in:
Lorenzo Blasa
2022-05-09 05:27:21 -07:00
committed by Facebook GitHub Bot
parent 274c0a242e
commit 1beae3230b

View File

@@ -10,17 +10,22 @@
#include <fcntl.h> #include <fcntl.h>
#include <folly/portability/Fcntl.h> #include <folly/portability/Fcntl.h>
#include <folly/portability/SysStat.h> #include <folly/portability/SysStat.h>
#include <openssl/bio.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/pkcs12.h> #include <openssl/pkcs12.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/x509.h> #include <openssl/x509.h>
#include <stdio.h>
#include <cstring> #include <cstring>
#include <stdexcept> #include <stdexcept>
namespace facebook { namespace facebook {
namespace flipper { namespace flipper {
BIO* bioFromFile(const char* filename);
bool bioToFile(const char* filename, BIO* bio);
void generateCertSigningRequest_free( void generateCertSigningRequest_free(
EVP_PKEY* pKey, EVP_PKEY* pKey,
X509_REQ* x509_req, X509_REQ* x509_req,
@@ -35,6 +40,50 @@ void generateCertPKCS12_free(
STACK_OF(X509) * cacertstack, STACK_OF(X509) * cacertstack,
PKCS12* pkcs12bundle); PKCS12* pkcs12bundle);
BIO* bioFromFile(const char* filename) {
if (filename == nullptr) {
return nullptr;
}
FILE* fp = fopen(filename, "rb");
if (fp == nullptr) {
return nullptr;
}
BIO* bio = BIO_new(BIO_s_mem());
#define BUFFER_SIZE 512
char buffer[BUFFER_SIZE];
size_t r = 0;
while ((r = fread(buffer, 1, BUFFER_SIZE, fp)) > 0) {
BIO_write(bio, buffer, (int)r);
}
fclose(fp);
return bio;
}
bool bioToFile(const char* filename, BIO* bio) {
if (bio == nullptr || filename == nullptr) {
return false;
}
FILE* fp = fopen(filename, "wb");
if (fp == nullptr) {
return false;
}
BUF_MEM* bptr;
BIO_get_mem_ptr(bio, &bptr);
if (bptr != nullptr) {
fwrite(bptr->data, 1, bptr->length, fp);
}
fclose(fp);
return true;
}
bool generateCertSigningRequest( bool generateCertSigningRequest(
const char* appId, const char* appId,
const char* csrFile, const char* csrFile,
@@ -62,7 +111,7 @@ bool generateCertSigningRequest(
BIO* privateKey = NULL; BIO* privateKey = NULL;
BIO* csrBio = NULL; BIO* csrBio = NULL;
EVP_PKEY_assign_RSA(pKey, rsa); EVP_PKEY_assign(pKey, EVP_PKEY_RSA, rsa);
// Generate rsa key // Generate rsa key
bne = BN_new(); bne = BN_new();
@@ -70,34 +119,27 @@ bool generateCertSigningRequest(
ret = BN_set_word(bne, e); ret = BN_set_word(bne, e);
if (ret != 1) { if (ret != 1) {
generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio); generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio);
return ret; return false;
} }
ret = RSA_generate_key_ex(rsa, bits, bne, NULL); ret = RSA_generate_key_ex(rsa, bits, bne, NULL);
if (ret != 1) { if (ret != 1) {
generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio); generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio);
return ret; return false;
} }
{ {
// Write private key to a file privateKey = BIO_new(BIO_s_mem());
int privateKeyFd =
open(privateKeyFile, O_CREAT | O_WRONLY, S_IWUSR | S_IRUSR);
if (privateKeyFd < 0) {
generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio);
return -1;
}
FILE* privateKeyFp = fdopen(privateKeyFd, "w");
if (privateKeyFp == NULL) {
generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio);
return -1;
}
privateKey = BIO_new_fp(privateKeyFp, BIO_CLOSE);
ret = ret =
PEM_write_bio_RSAPrivateKey(privateKey, rsa, NULL, NULL, 0, NULL, NULL); PEM_write_bio_RSAPrivateKey(privateKey, rsa, NULL, NULL, 0, NULL, NULL);
if (ret != 1) { if (ret != 1) {
generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio); generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio);
return ret; return false;
}
if (!bioToFile(privateKeyFile, privateKey)) {
generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio);
return false;
} }
} }
@@ -197,22 +239,18 @@ bool generateCertSigningRequest(
{ {
// Write CSR to a file // Write CSR to a file
int csrFd = open(csrFile, O_CREAT | O_WRONLY, S_IWUSR | S_IRUSR); csrBio = BIO_new(BIO_s_mem());
if (csrFd < 0) {
generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio);
return -1;
}
FILE* csrFp = fdopen(csrFd, "w");
if (csrFp == NULL) {
generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio);
return -1;
}
csrBio = BIO_new_fp(csrFp, BIO_CLOSE);
ret = PEM_write_bio_X509_REQ(csrBio, x509_req); ret = PEM_write_bio_X509_REQ(csrBio, x509_req);
if (ret != 1) { if (ret != 1) {
generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio); generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio);
return ret; return ret;
} }
if (!bioToFile(csrFile, csrBio)) {
generateCertSigningRequest_free(pKey, x509_req, bne, privateKey, csrBio);
return false;
}
} }
ret = BIO_flush(csrBio); ret = BIO_flush(csrBio);
@@ -245,73 +283,59 @@ bool generateCertPKCS12(
STACK_OF(X509)* cacertstack = NULL; STACK_OF(X509)* cacertstack = NULL;
PKCS12* pkcs12bundle = NULL; PKCS12* pkcs12bundle = NULL;
EVP_PKEY* cert_privkey = NULL; EVP_PKEY* cert_privkey = NULL;
FILE *cacertfile = NULL, *certfile = NULL, *keyfile = NULL,
*pkcs12file = NULL;
int bytes = 0; int bytes = 0;
/* 1) These function calls are essential to make PEM_read and
* other openssl functions work.
*/
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
ERR_load_crypto_strings(); ERR_load_crypto_strings();
/* 2) load the certificate's private key // Load the certificate's private key
*/
if ((cert_privkey = EVP_PKEY_new()) == NULL) { if ((cert_privkey = EVP_PKEY_new()) == NULL) {
return false; return false;
} }
if (!(keyfile = fopen(keyFilepath, "r"))) { BIO* privateKeyBio = bioFromFile(keyFilepath);
if (privateKeyBio == nullptr) {
generateCertPKCS12_free( generateCertPKCS12_free(
cacert, cert, cert_privkey, cacertstack, pkcs12bundle); cacert, cert, cert_privkey, cacertstack, pkcs12bundle);
return false; return false;
} }
if (!(cert_privkey = PEM_read_PrivateKey(keyfile, NULL, NULL, NULL))) { if (!(cert_privkey =
fclose(keyfile); PEM_read_bio_PrivateKey(privateKeyBio, NULL, NULL, NULL))) {
generateCertPKCS12_free( generateCertPKCS12_free(
cacert, cert, cert_privkey, cacertstack, pkcs12bundle); cacert, cert, cert_privkey, cacertstack, pkcs12bundle);
return false; return false;
} }
fclose(keyfile); // Load the certificate
BIO* certificateBio = bioFromFile(certFilepath);
/* 3) Load the corresponding certificate if (certificateBio == nullptr) {
*/
if (!(certfile = fopen(certFilepath, "r"))) {
generateCertPKCS12_free( generateCertPKCS12_free(
cacert, cert, cert_privkey, cacertstack, pkcs12bundle); cacert, cert, cert_privkey, cacertstack, pkcs12bundle);
return false; return false;
} }
if (!(cert = PEM_read_X509(certfile, NULL, NULL, NULL))) { if (!(cert = PEM_read_bio_X509(certificateBio, NULL, NULL, NULL))) {
fclose(certfile);
generateCertPKCS12_free( generateCertPKCS12_free(
cacert, cert, cert_privkey, cacertstack, pkcs12bundle); cacert, cert, cert_privkey, cacertstack, pkcs12bundle);
return false; return false;
} }
fclose(certfile); // Load the CA certificate who signed it
BIO* cacertBio = bioFromFile(cacertFilepath);
/* 4) Load the CA certificate who signed it if (cacertBio == nullptr) {
*/
if (!(cacertfile = fopen(cacertFilepath, "r"))) {
generateCertPKCS12_free( generateCertPKCS12_free(
cacert, cert, cert_privkey, cacertstack, pkcs12bundle); cacert, cert, cert_privkey, cacertstack, pkcs12bundle);
return false; return false;
} }
if (!(cacert = PEM_read_X509(cacertfile, NULL, NULL, NULL))) { if (!(cacert = PEM_read_bio_X509(cacertBio, NULL, NULL, NULL))) {
fclose(cacertfile);
generateCertPKCS12_free( generateCertPKCS12_free(
cacert, cert, cert_privkey, cacertstack, pkcs12bundle); cacert, cert, cert_privkey, cacertstack, pkcs12bundle);
return false; return false;
} }
fclose(cacertfile); // Load the CA certificate on the stack
/* 5) Load the CA certificate on the stack
*/
if ((cacertstack = sk_X509_new_null()) == NULL) { if ((cacertstack = sk_X509_new_null()) == NULL) {
generateCertPKCS12_free( generateCertPKCS12_free(
cacert, cert, cert_privkey, cacertstack, pkcs12bundle); cacert, cert, cert_privkey, cacertstack, pkcs12bundle);
@@ -320,15 +344,14 @@ bool generateCertPKCS12(
sk_X509_push(cacertstack, cacert); sk_X509_push(cacertstack, cacert);
/* 6) we create the PKCS12 structure and fill it with our data // Create the PKCS12 structure and fill it with our data
*/
if ((pkcs12bundle = PKCS12_new()) == NULL) { if ((pkcs12bundle = PKCS12_new()) == NULL) {
generateCertPKCS12_free( generateCertPKCS12_free(
cacert, cert, cert_privkey, cacertstack, pkcs12bundle); cacert, cert, cert_privkey, cacertstack, pkcs12bundle);
return false; return false;
} }
/* values of zero use the openssl default values */ // Values of zero use the openssl default values
pkcs12bundle = PKCS12_create( pkcs12bundle = PKCS12_create(
const_cast<char*>(pkcs12Password), // certbundle access password const_cast<char*>(pkcs12Password), // certbundle access password
const_cast<char*>(pkcs12Name), // friendly certificate name const_cast<char*>(pkcs12Name), // friendly certificate name
@@ -348,24 +371,24 @@ bool generateCertPKCS12(
return false; return false;
} }
/* 7) Write the PKCS12 structure out to file // Write the PKCS12 structure out to file
*/ BIO* pkcs12Bio = BIO_new(BIO_s_mem());
if (!(pkcs12file = fopen(pkcs12Filepath, "w"))) { bytes = i2d_PKCS12_bio(pkcs12Bio, pkcs12bundle);
generateCertPKCS12_free(
cacert, cert, cert_privkey, cacertstack, pkcs12bundle);
return false;
}
bytes = i2d_PKCS12_fp(pkcs12file, pkcs12bundle);
if (bytes <= 0) { if (bytes <= 0) {
generateCertPKCS12_free( generateCertPKCS12_free(
cacert, cert, cert_privkey, cacertstack, pkcs12bundle); cacert, cert, cert_privkey, cacertstack, pkcs12bundle);
return false; return false;
} }
/* 8) Done, free resources. if (!bioToFile(pkcs12Filepath, pkcs12Bio)) {
*/ BIO_free(pkcs12Bio);
fclose(pkcs12file); generateCertPKCS12_free(
cacert, cert, cert_privkey, cacertstack, pkcs12bundle);
return false;
}
// Done, free resources
BIO_free(pkcs12Bio);
generateCertPKCS12_free( generateCertPKCS12_free(
cacert, cert, cert_privkey, cacertstack, pkcs12bundle); cacert, cert, cert_privkey, cacertstack, pkcs12bundle);