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:
committed by
Facebook GitHub Bot
parent
274c0a242e
commit
1beae3230b
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user