zxid
view release on metacpan or search on metacpan
smimeutil.c view on Meta::CPAN
#include "smimeutil.h"
/* ======================= U T I L I T I E S ======================= */
char smime_error_buf[256]; /* stores smime library-level error */
char randomfile[256] = "random.txt";
#ifdef DEBUGLOG
FILE* Log = NULL;
#endif
/* initializes EVP algorithm tables and injects randomness into
* system. If random file existed it is read as well and 0 (for
* success) is returned. If random file did not exist, it will be
* created (if permissions allow) and -1 is returned. On that occasion
* it is advisable to arrange some real randomness (such as movements of
* mouse, times between key presses, /dev/random, etc.) and call
* init again.
*/
/* Called by: main */
int smime_init(const char* random_file, const char* randomness, int randlen)
{
time_t t;
OpenSSL_add_all_algorithms(); /* calling this multiple times does not seem to have any negative effect. */
OpenSSL_add_all_ciphers(); /* Needed to avoid 10069:error:0906B072:PEM routines:PEM_get_EVP_CIPHER_INFO:unsupported encryption:pem_lib.c:481: */
OpenSSL_add_all_digests();
#ifdef DEBUGLOG
Log = fopen("smimeutil.log", "w");
LOG("Log opened");
#endif
LOG_PRINT("smime_init");
t = time(NULL);
RAND_seed(&t,sizeof(t));
if (randomness) RAND_seed(randomness, randlen);
#ifdef WINDOWS
LOG_PRINT("RAND_screen...");
RAND_screen(); /* Loading video display memory into random state */
#endif
if (random_file) {
strncpy(randomfile, random_file, sizeof(randomfile));
randomfile[sizeof(randomfile)-1] = '\0';
}
if (RAND_load_file(randomfile,1024L*1024L)) {
RAND_seed(&t,sizeof(t));
strcpy(smime_error_buf, SMIME_VERSION " randomness initialized");
return 0;
}
strcpy(smime_error_buf, SMIME_VERSION " no randomfile");
RAND_seed(&t,sizeof(t));
RAND_write_file(randomfile); /* create random file if possible */
return -1;
}
/* Initialize a memory BIO to have certain content */
/* Called by: encrypt1, extract_certificate, extract_request, get_pkcs7_from_pem, load_PKCS12, open_private_key, smime_base64, smime_pkcs12_to_pem_generic, smime_sign_engine, smime_verify_signature */
BIO* set_read_BIO_from_buf(const char* buf, int len)
{
BIO* rbio;
BUF_MEM* bm;
if (!buf) GOTO_ERR("NULL file buffer");
if (len == -1) len = strlen(buf);
LOG_PRINT3("set_read_BIO_from_buf %x, len %d", buf, len);
if (!(rbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
if (!(bm = BUF_MEM_new())) GOTO_ERR("no memory?");
if (!BUF_MEM_grow(bm, len)) GOTO_ERR("no memory?");
memcpy(bm->data, buf, len);
BIO_set_mem_buf(rbio, bm, 0 /*not used*/);
LOG_PRINT("ok");
return rbio;
err:
return NULL;
}
/* Flushes a write BIO and returns the accumulated data as one malloc'd blob
* returns length or -1 if error */
/* Called by: decrypt, get_cert_info, get_req_modulus, save_PKCS12, smime_base64, smime_pkcs12_to_pem_generic x2, smime_verify_signature, write_certificate, write_private_key, write_request */
int get_written_BIO_data(BIO* wbio, char** data)
{
int n;
char* p;
if (!data) GOTO_ERR("NULL arg");
*data = NULL;
BIO_flush(wbio);
n = BIO_get_mem_data(wbio,&p);
LOG_PRINT3("get_written_BIO_data: %x %d bytes", p, n);
if (!((*data)=(char*)OPENSSL_malloc(n+1))) GOTO_ERR("no memory?");
memcpy(*data, p, n);
(*data)[n] = '\0';
return n;
err:
return -1;
}
/* Callback for supplying the pesky password. */
/* Called by: */
int password_callback(char* buf, int buf_size, int x /*not used*/, void* password)
{
int n;
if (!password) {
strcpy(buf, "");
return 0;
}
n = strlen((char*)password);
if (n >= buf_size) n = buf_size-1;
memcpy(buf, (char*)password, n);
buf[n] = '\0';
return n;
}
/* Get private key from buffer full of encrypted stuff */
/* Called by: smime_ca, smime_clear_sign, smime_decrypt, smime_sign */
EVP_PKEY* open_private_key(const char* privatekey_pem, const char* password)
{
EVP_PKEY* pkey = NULL;
BIO* rbio = NULL;
LOG_PRINT3("open_private_key: %x %x", privatekey_pem, password);
#ifdef CR_PARANOIA
if (!(privatekey_pem = mime_canon(privatekey_pem))) GOTO_ERR("no memory?");
LOG_PRINT("CR paranoia enabled");
#endif
if (!(rbio = set_read_BIO_from_buf(privatekey_pem, -1))) goto err;
if (!(pkey=PEM_read_bio_PrivateKey(rbio,NULL, password_callback,
(void*)password)))
GOTO_ERR("01 bad password or badly formatted private key pem file (PEM_read_bio_PrivateKey)");
LOG_PRINT("done");
BIO_free(rbio);
#ifdef CR_PARANOIA
if (privatekey_pem) Free((void*)privatekey_pem);
#endif
return pkey;
err:
#ifdef CR_PARANOIA
if (privatekey_pem) Free((void*)privatekey_pem);
#endif
if (pkey) EVP_PKEY_free(pkey);
if (rbio) BIO_free(rbio);
LOG_PRINT("error");
return NULL;
}
/* Called by: smime_keygen, smime_pkcs12_to_pem */
int write_private_key(EVP_PKEY* pkey, const char* passwd, char** priv_pem_OUT)
{
int len = -1;
BIO* wbio=NULL;
if (!passwd || !priv_pem_OUT || !pkey) GOTO_ERR("NULL arg(s)");
*priv_pem_OUT = NULL;
if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
LOG_PRINT("write_private_key");
if (!PEM_write_bio_PrivateKey(wbio, pkey, *passwd ? EVP_des_ede3_cbc() : 0,
*passwd ? (unsigned char*)passwd:0, strlen(passwd),
NULL,NULL))
GOTO_ERR("PEM_write_bio_PrivateKey (bad passwd, no memory?)");
len = get_written_BIO_data(wbio, priv_pem_OUT);
err:
if (wbio) BIO_free_all(wbio);
return len;
}
/* Extract a certificate from pem encoding */
/* Called by: smime_ca, smime_clear_sign, smime_decrypt, smime_encrypt, smime_get_cert_info, smime_get_cert_names, smime_sign, smime_verify_cert x2, smime_verify_signature */
X509* extract_certificate(const char* cert_pem)
{
X509* x509 = NULL;
BIO* rbio = NULL;
LOG_PRINT2("extract_certificate %x", cert_pem);
#ifdef CR_PARANOIA
if (!(cert_pem = mime_canon(cert_pem))) GOTO_ERR("no memory?");
LOG_PRINT("CR paranoia enabled");
#endif
if (!(rbio = set_read_BIO_from_buf(cert_pem, -1))) goto err;
if (!(x509=PEM_read_bio_X509(rbio,NULL,NULL,NULL)))
GOTO_ERR("10 badly formatted X509 certificate pem file (PEM_read_bio_X509)");
LOG_PRINT("done");
err:
#ifdef CR_PARANOIA
if (cert_pem) Free((void*)cert_pem);
#endif
if (rbio) BIO_free(rbio);
return x509;
}
/* Called by: smime_ca, smime_keygen, smime_pkcs12_to_pem */
int write_certificate(X509* x509, char** x509_cert_pem_OUT)
{
BIO* wbio = NULL;
int len = -1;
if (!x509 || !x509_cert_pem_OUT) GOTO_ERR("NULL arg");
*x509_cert_pem_OUT = NULL;
if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
LOG_PRINT("write_certificate");
PEM_write_bio_X509(wbio, x509);
len = get_written_BIO_data(wbio, x509_cert_pem_OUT);
err:
if (wbio) BIO_free_all(wbio);
return len;
}
/* Called by: smime_ca, smime_get_req_attr, smime_get_req_modulus, smime_get_req_name */
X509_REQ* extract_request(const char* req_pem)
{
X509_REQ* x509_req = NULL;
BIO* rbio = NULL;
LOG_PRINT2("extract_request %x", req_pem);
#ifdef CR_PARANOIA
if (!(req_pem = mime_canon(req_pem))) GOTO_ERR("no memory?");
LOG_PRINT("CR paranoia enabled");
#endif
( run in 0.996 second using v1.01-cache-2.11-cpan-ceb78f64989 )