LCOV - code coverage report
Current view: top level - zxid - smimeutil.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 109 159 68.6 %
Date: 2010-12-19 Functions: 11 15 73.3 %
Branches: 44 108 40.7 %

           Branch data     Line data    Source code
       1                 :            : /* smimeutil.c  -  Utility functions for performing S/MIME signatures
       2                 :            :  *                 and encryption.
       3                 :            :  *
       4                 :            :  * Copyright (c) 1999,2004 Sampo Kellomaki <sampo@iki.fi>, All Rights Reserved.
       5                 :            :  * License: This software may be distributed under the same license
       6                 :            :  *          terms as openssl (i.e. free, but mandatory attribution).
       7                 :            :  *          See file LICENSE for details.
       8                 :            :  *
       9                 :            :  * 11.9.1999, Created. --Sampo
      10                 :            :  * 13.9.1999, 0.1 released. Now adding verify. --Sampo
      11                 :            :  * 1.10.1999, improved error handling, fixed decrypt --Sampo
      12                 :            :  * 6.10.1999, divided to smime-enc.c, smime-vfy.c, smimemime.c and smimeutil.c
      13                 :            :  * 9.10.1999, reviewed for double frees --Sampo
      14                 :            :  * 18.10.1999, added CR_PARANOIA ifdefs. THis define is useful on platforms
      15                 :            :  *             like Mac that use CR as line termination. OpenSSL PEM
      16                 :            :  *             parsing routines do not grog CR so we need to preconvert
      17                 :            :  *             CR to CRLF to guarantee easy operation. --Sampo
      18                 :            :  * 10.10.2004, fixed long term annoyance where empty password did still encypt. Now
      19                 :            :  *             empty password causes no encryption what so ever. --Sampo
      20                 :            :  *
      21                 :            :  * This module has been developed to support a Lingo XTRA that is supposed
      22                 :            :  * to provide crypto functionality. It may, however, be useful for other
      23                 :            :  * purposes as well.
      24                 :            :  *
      25                 :            :  * This is a very simple S/MIME library. For example the multipart
      26                 :            :  * boundary separators are hard coded and no effort is made to verify
      27                 :            :  * that mime entities are in their canonical form before signing (the
      28                 :            :  * caller should make sure they are, canonical form means using CRLF
      29                 :            :  * as line termination, among other things). Also the multipart functionality
      30                 :            :  * only understands up to 3 attachments. For many tasks this is enough,
      31                 :            :  * but if its not, feel free to write more generic utilities.
      32                 :            :  *
      33                 :            :  * Memory management: most routines malloc the results. Freeing them is
      34                 :            :  * application's responsibility. I use libc malloc, but if in doubt
      35                 :            :  * it might be safer to just leak the memory (i.e. don't ever free it).
      36                 :            :  * This library works entirely in memory, so maximum memory consumption
      37                 :            :  * might be more than twice the total size of all files to be encrypted.
      38                 :            :  */
      39                 :            : 
      40                 :            : #include "platform.h"
      41                 :            : 
      42                 :            : #include <stdio.h>
      43                 :            : #include <string.h>
      44                 :            : #include <time.h>
      45                 :            : 
      46                 :            : #if defined(macintosh) || defined(__MWERKS__)
      47                 :            : #include "macglue.h"
      48                 :            : #endif
      49                 :            : 
      50                 :            : #include "logprint.h"
      51                 :            : 
      52                 :            : #include <openssl/crypto.h>
      53                 :            : #include <openssl/buffer.h>
      54                 :            : #include <openssl/bio.h>
      55                 :            : #include <openssl/x509.h>
      56                 :            : #include <openssl/pem.h>
      57                 :            : #include <openssl/err.h>
      58                 :            : #include <openssl/rand.h>
      59                 :            : 
      60                 :            : #define SMIME_INTERNALS  /* we want also our internal helper functions */
      61                 :            : #include "smimeutil.h"
      62                 :            : 
      63                 :            : /* ======================= U T I L I T I E S ======================= */
      64                 :            : 
      65                 :            : char smime_error_buf[256];  /* stores smime library-level error */
      66                 :            : char randomfile[256] = "random.txt";
      67                 :            : 
      68                 :            : #ifdef DEBUGLOG
      69                 :            : FILE* Log = NULL;
      70                 :            : #endif
      71                 :            : 
      72                 :            : /* initializes EVP algorithm tables and injects randomness into
      73                 :            :  * system. If random file existed it is read as well and 0 (for
      74                 :            :  * success) is returned. If random file did not exist, it will be
      75                 :            :  * created (if permissions allow) and -1 is returned. On that occasion
      76                 :            :  * it is advisable to arrange some real randomness (such as movements of
      77                 :            :  * mouse, times between key presses, /dev/random, etc.) and call
      78                 :            :  * init again.
      79                 :            :  */
      80                 :            : 
      81                 :            : /* Called by:  main */
      82                 :            : int smime_init(const char* random_file, const char* randomness, int randlen)
      83                 :         35 : {
      84                 :            :   time_t t;
      85                 :         35 :   OpenSSL_add_all_algorithms();  /* calling this multiple times does not seem to have any negative effect. */
      86                 :         35 :   OpenSSL_add_all_ciphers();  /* Needed to avoid 10069:error:0906B072:PEM routines:PEM_get_EVP_CIPHER_INFO:unsupported encryption:pem_lib.c:481: */
      87                 :         35 :   OpenSSL_add_all_digests();
      88                 :            : 
      89                 :            : #ifdef DEBUGLOG
      90                 :            :   Log = fopen("smimeutil.log", "w");
      91                 :            :   LOG("Log opened");
      92                 :            : #endif
      93                 :            : 
      94                 :            :   LOG_PRINT("smime_init");
      95                 :         35 :   t = time(NULL);
      96                 :         35 :   RAND_seed(&t,sizeof(t));
      97         [ +  - ]:         35 :   if (randomness) RAND_seed(randomness, randlen);
      98                 :            : 
      99                 :            : #ifdef WINDOWS
     100                 :            :   LOG_PRINT("RAND_screen...");
     101                 :            :   RAND_screen(); /* Loading video display memory into random state */
     102                 :            : #endif
     103         [ +  - ]:         35 :   if (random_file) {
     104                 :         35 :     strncpy(randomfile, random_file, sizeof(randomfile));
     105                 :         35 :     randomfile[sizeof(randomfile)-1] = '\0';
     106                 :            :   }
     107         [ +  - ]:         35 :   if (RAND_load_file(randomfile,1024L*1024L)) {
     108                 :         35 :     RAND_seed(&t,sizeof(t));
     109                 :         35 :     strcpy(smime_error_buf, SMIME_VERSION " randomness initialized");
     110                 :         35 :     return 0;
     111                 :            :   }
     112                 :          0 :   strcpy(smime_error_buf, SMIME_VERSION " no randomfile");
     113                 :          0 :   RAND_seed(&t,sizeof(t));
     114                 :          0 :   RAND_write_file(randomfile);  /* create random file if possible */
     115                 :            : 
     116                 :          0 :   return -1;
     117                 :            : }
     118                 :            : 
     119                 :            : /* Initialize a memory BIO to have certain content */
     120                 :            : 
     121                 :            : /* 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 */
     122                 :            : BIO* set_read_BIO_from_buf(const char* buf, int len)
     123                 :         33 : {
     124                 :            :   BIO* rbio;  
     125                 :            :   BUF_MEM* bm;
     126         [ -  + ]:         33 :   if (!buf) GOTO_ERR("NULL file buffer");
     127         [ +  + ]:         33 :   if (len == -1) len = strlen(buf);
     128                 :            :   LOG_PRINT3("set_read_BIO_from_buf %x, len %d", buf, len);
     129         [ -  + ]:         33 :   if (!(rbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
     130         [ -  + ]:         33 :   if (!(bm = BUF_MEM_new()))  GOTO_ERR("no memory?");
     131         [ +  + ]:         33 :   if (!BUF_MEM_grow(bm, len)) GOTO_ERR("no memory?");
     132                 :         29 :   memcpy(bm->data, buf, len);
     133                 :         29 :   BIO_set_mem_buf(rbio, bm, 0 /*not used*/);
     134                 :            :   LOG_PRINT("ok");
     135                 :         29 :   return rbio;
     136                 :          4 : err:
     137                 :          4 :   return NULL;
     138                 :            : }
     139                 :            : 
     140                 :            : /* Flushes a write BIO and returns the accumulated data as one malloc'd blob
     141                 :            :  * returns length or -1 if error */
     142                 :            : 
     143                 :            : /* 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 */
     144                 :            : int get_written_BIO_data(BIO* wbio, char** data)
     145                 :         12 : {
     146                 :            :   int n;
     147                 :            :   char* p;
     148         [ -  + ]:         12 :   if (!data) GOTO_ERR("NULL arg");
     149                 :         12 :   *data = NULL;
     150                 :         12 :   BIO_flush(wbio);
     151                 :         12 :   n = BIO_get_mem_data(wbio,&p);
     152                 :            :   LOG_PRINT3("get_written_BIO_data: %x %d bytes", p, n);
     153         [ -  + ]:         12 :   if (!((*data)=(char*)OPENSSL_malloc(n+1))) GOTO_ERR("no memory?");
     154                 :         12 :   memcpy(*data, p, n);
     155                 :         12 :   (*data)[n] = '\0';
     156                 :         12 :   return n;
     157                 :          0 : err:
     158                 :          0 :   return -1;
     159                 :            : }
     160                 :            : 
     161                 :            : /* Callback for supplying the pesky password. */
     162                 :            : 
     163                 :            : /* Called by: */
     164                 :            : int password_callback(char* buf, int buf_size, int x /*not used*/, void* password)
     165                 :          0 : {
     166                 :            :   int n;
     167         [ #  # ]:          0 :   if (!password) {
     168                 :          0 :     strcpy(buf, "");
     169                 :          0 :     return 0;
     170                 :            :   }
     171                 :          0 :   n = strlen((char*)password);
     172         [ #  # ]:          0 :   if (n >= buf_size) n = buf_size-1;
     173                 :          0 :   memcpy(buf, (char*)password, n);
     174                 :          0 :   buf[n] = '\0';
     175                 :          0 :   return n; 
     176                 :            : }
     177                 :            : 
     178                 :            : /* Get private key from buffer full of encrypted stuff */
     179                 :            : 
     180                 :            : /* Called by:  smime_ca, smime_clear_sign, smime_decrypt, smime_sign */
     181                 :            : EVP_PKEY* open_private_key(const char* privatekey_pem, const char* password)
     182                 :          9 : {
     183                 :          9 :   EVP_PKEY* pkey = NULL;
     184                 :          9 :   BIO* rbio = NULL;
     185                 :            :   LOG_PRINT3("open_private_key: %x %x", privatekey_pem, password);
     186                 :            : #ifdef CR_PARANOIA
     187                 :            :   if (!(privatekey_pem = mime_canon(privatekey_pem))) GOTO_ERR("no memory?");
     188                 :            :   LOG_PRINT("CR paranoia enabled");
     189                 :            : #endif
     190         [ +  - ]:          9 :   if (!(rbio = set_read_BIO_from_buf(privatekey_pem, -1))) goto err;
     191         [ +  - ]:          9 :   if (!(pkey=PEM_read_bio_PrivateKey(rbio,NULL, password_callback,
     192                 :            :                                      (void*)password)))
     193                 :          9 :     GOTO_ERR("01 bad password or badly formatted private key pem file (PEM_read_bio_PrivateKey)");
     194                 :            :   LOG_PRINT("done");
     195                 :          0 :   BIO_free(rbio);
     196                 :            : #ifdef CR_PARANOIA
     197                 :            :   if (privatekey_pem) Free((void*)privatekey_pem);
     198                 :            : #endif
     199                 :          0 :   return pkey;
     200                 :            :   
     201                 :          9 : err:
     202                 :            : #ifdef CR_PARANOIA
     203                 :            :   if (privatekey_pem) Free((void*)privatekey_pem);
     204                 :            : #endif
     205         [ -  + ]:          9 :   if (pkey) EVP_PKEY_free(pkey);
     206         [ +  - ]:          9 :   if (rbio) BIO_free(rbio);
     207                 :            :   LOG_PRINT("error");
     208                 :          9 :   return NULL;
     209                 :            : }
     210                 :            : 
     211                 :            : /* Called by:  smime_keygen, smime_pkcs12_to_pem */
     212                 :            : int write_private_key(EVP_PKEY* pkey, const char* passwd, char** priv_pem_OUT)
     213                 :          2 : {
     214                 :          2 :   int len = -1;
     215                 :          2 :   BIO* wbio=NULL;
     216   [ +  -  +  -  :          2 :   if (!passwd || !priv_pem_OUT || !pkey) GOTO_ERR("NULL arg(s)");
                   -  + ]
     217                 :          2 :   *priv_pem_OUT = NULL;
     218         [ -  + ]:          2 :   if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
     219                 :            :   LOG_PRINT("write_private_key");
     220   [ +  -  +  -  :          2 :   if (!PEM_write_bio_PrivateKey(wbio, pkey, *passwd ? EVP_des_ede3_cbc() : 0,
                   -  + ]
     221                 :            :                                 *passwd ? (unsigned char*)passwd:0, strlen(passwd),
     222                 :            :                                 NULL,NULL))
     223                 :          0 :     GOTO_ERR("PEM_write_bio_PrivateKey (bad passwd, no memory?)");
     224                 :          2 :   len = get_written_BIO_data(wbio, priv_pem_OUT);
     225                 :          2 : err:
     226         [ +  - ]:          2 :   if (wbio) BIO_free_all(wbio);
     227                 :          2 :   return len;
     228                 :            : }
     229                 :            : 
     230                 :            : /* Extract a certificate from pem encoding */
     231                 :            : 
     232                 :            : /* 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 */
     233                 :            : X509* extract_certificate(const char* cert_pem)
     234                 :          8 : {
     235                 :          8 :   X509* x509 = NULL;
     236                 :          8 :   BIO* rbio = NULL;
     237                 :            :   LOG_PRINT2("extract_certificate %x", cert_pem);
     238                 :            : #ifdef CR_PARANOIA
     239                 :            :   if (!(cert_pem = mime_canon(cert_pem))) GOTO_ERR("no memory?");
     240                 :            :   LOG_PRINT("CR paranoia enabled");
     241                 :            : #endif
     242         [ +  + ]:          8 :   if (!(rbio = set_read_BIO_from_buf(cert_pem, -1))) goto err;
     243         [ +  + ]:          7 :   if (!(x509=PEM_read_bio_X509(rbio,NULL,NULL,NULL)))
     244                 :          1 :     GOTO_ERR("10 badly formatted X509 certificate pem file (PEM_read_bio_X509)");
     245                 :            :   LOG_PRINT("done");
     246                 :          8 : err:
     247                 :            : #ifdef CR_PARANOIA
     248                 :            :   if (cert_pem) Free((void*)cert_pem);
     249                 :            : #endif
     250         [ +  + ]:          8 :   if (rbio) BIO_free(rbio);
     251                 :          8 :   return x509;
     252                 :            : }
     253                 :            : 
     254                 :            : /* Called by:  smime_ca, smime_keygen, smime_pkcs12_to_pem */
     255                 :            : int write_certificate(X509* x509, char** x509_cert_pem_OUT)
     256                 :          2 : {
     257                 :          2 :   BIO* wbio = NULL;
     258                 :          2 :   int len = -1;
     259   [ +  -  -  + ]:          2 :   if (!x509 || !x509_cert_pem_OUT) GOTO_ERR("NULL arg");
     260                 :          2 :   *x509_cert_pem_OUT = NULL;
     261         [ -  + ]:          2 :   if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
     262                 :            :   LOG_PRINT("write_certificate");
     263                 :          2 :   PEM_write_bio_X509(wbio, x509);
     264                 :          2 :   len = get_written_BIO_data(wbio, x509_cert_pem_OUT);
     265                 :          2 : err:
     266         [ +  - ]:          2 :   if (wbio) BIO_free_all(wbio);
     267                 :          2 :   return len;
     268                 :            : }
     269                 :            : 
     270                 :            : /* Called by:  smime_ca, smime_get_req_attr, smime_get_req_modulus, smime_get_req_name */
     271                 :            : X509_REQ* extract_request(const char* req_pem)
     272                 :          1 : {
     273                 :          1 :   X509_REQ* x509_req = NULL;
     274                 :          1 :   BIO* rbio = NULL;
     275                 :            :   LOG_PRINT2("extract_request %x", req_pem);
     276                 :            : #ifdef CR_PARANOIA
     277                 :            :   if (!(req_pem = mime_canon(req_pem))) GOTO_ERR("no memory?");
     278                 :            :   LOG_PRINT("CR paranoia enabled");
     279                 :            : #endif
     280         [ +  - ]:          1 :   if (!(rbio = set_read_BIO_from_buf(req_pem, -1))) goto err;
     281         [ +  - ]:          1 :   if (!(x509_req = PEM_read_bio_X509_REQ(rbio,NULL,NULL,NULL)))
     282                 :          1 :     GOTO_ERR("04 badly formatted certificate request pem file (PEM_read_bio_x509_REQ)");
     283                 :            :   LOG_PRINT("done");  
     284                 :          1 : err:
     285                 :            : #ifdef CR_PARANOIA
     286                 :            :   if (req_pem) Free((void*)req_pem);
     287                 :            : #endif
     288         [ +  - ]:          1 :   if (rbio) BIO_free(rbio);
     289                 :          1 :   return x509_req;
     290                 :            : }
     291                 :            : 
     292                 :            : /* Called by:  smime_keygen */
     293                 :            : int write_request(X509_REQ* x509_req, char** x509_req_pem_OUT)
     294                 :          2 : {
     295                 :          2 :   BIO* wbio = NULL;
     296                 :          2 :   int len = -1;
     297   [ +  -  -  + ]:          2 :   if (!x509_req || !x509_req_pem_OUT) GOTO_ERR("NULL arg");
     298                 :          2 :   *x509_req_pem_OUT = NULL;
     299         [ -  + ]:          2 :   if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
     300                 :            :   LOG_PRINT("write_request");
     301                 :          2 :   PEM_write_bio_X509_REQ(wbio, x509_req);
     302                 :          2 :   len = get_written_BIO_data(wbio, x509_req_pem_OUT);  
     303                 :          2 : err:
     304         [ +  - ]:          2 :   if (wbio) BIO_free_all(wbio);
     305                 :          2 :   return len;
     306                 :            : }
     307                 :            : 
     308                 :            : /* Called by:  smime_pkcs12_to_pem */
     309                 :            : PKCS12* load_PKCS12(const char* pkcs12, int pkcs12_len)
     310                 :          1 : {
     311                 :          1 :   BIO* rbio = NULL;
     312                 :          1 :   PKCS12* p12 = NULL;
     313         [ -  + ]:          1 :   if (!(rbio = set_read_BIO_from_buf((char*)pkcs12, pkcs12_len))) goto err;
     314         [ #  # ]:          0 :   if (!(p12 = d2i_PKCS12_bio(rbio, NULL)))
     315                 :          0 :     GOTO_ERR("02 bad PKCS12 file format (d2i_PKCS12_bio)");
     316                 :          1 : err:
     317         [ -  + ]:          1 :   if (rbio) BIO_free(rbio);
     318                 :          1 :   return p12;
     319                 :            :   
     320                 :            : }
     321                 :            : 
     322                 :            : /* Called by: */
     323                 :            : int save_PKCS12(PKCS12* p12, char** pkcs12_out)
     324                 :          0 : {
     325                 :          0 :   BIO* wbio = NULL;
     326                 :          0 :   int len = -1;
     327   [ #  #  #  # ]:          0 :   if (!p12 || !pkcs12_out) GOTO_ERR("NULL arg(s)");
     328                 :          0 :   *pkcs12_out = NULL;
     329         [ #  # ]:          0 :   if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
     330                 :          0 :   i2d_PKCS12_bio(wbio, p12);  /* der encode it */
     331                 :          0 :   len = get_written_BIO_data(wbio, pkcs12_out);
     332                 :          0 : err:
     333         [ #  # ]:          0 :   if (wbio) BIO_free_all(wbio);
     334                 :          0 :   return len;
     335                 :            : }
     336                 :            : 
     337                 :            : /* Called by:  get_cert_info */
     338                 :            : char* smime_dotted_hex(const char* data, int len)
     339                 :          0 : {
     340                 :            :   int j;
     341                 :            :   char* p;
     342                 :            :   char* buf;
     343   [ #  #  #  # ]:          0 :   if (!data || !len) GOTO_ERR("NULL or bad arg");
     344         [ #  # ]:          0 :   if (!(buf = p = (char*)OPENSSL_malloc(len*3+1))) GOTO_ERR("no memory?");
     345         [ #  # ]:          0 :   for (j=0; j<len; j++) {
     346                 :          0 :     sprintf(p,"%02X:",(unsigned char)data[j]);
     347                 :          0 :     p+=3;
     348                 :            :   }
     349                 :          0 :   p[-1] = '\0';  /* change last : to \0 */
     350                 :          0 :   return buf;
     351                 :          0 : err:
     352                 :          0 :   return NULL;
     353                 :            : }
     354                 :            : 
     355                 :            : /* Called by:  smime_md5 */
     356                 :            : char* smime_hex(const char* data, int len)
     357                 :          0 : {
     358                 :            :   int j;
     359                 :            :   char* p;
     360                 :            :   char* buf;
     361   [ #  #  #  # ]:          0 :   if (!data || !len) GOTO_ERR("NULL or bad arg");
     362         [ #  # ]:          0 :   if (!(buf = p = (char*)OPENSSL_malloc(len*2+1))) GOTO_ERR("no memory?");
     363         [ #  # ]:          0 :   for (j=0; j<len; j++) {
     364                 :          0 :     sprintf(p,"%02X",(unsigned char)data[j]);
     365                 :          0 :     p+=2;
     366                 :            :   }
     367                 :          0 :   return buf;
     368                 :          0 : err:
     369                 :          0 :   return NULL;
     370                 :            : }
     371                 :            : 
     372                 :            : /* Called by:  main x28 */
     373                 :            : char* smime_get_errors()
     374                 :         18 : {
     375                 :            :   BIO* wbio;
     376                 :            :   char* p;
     377         [ -  + ]:         18 :   if (!(wbio = BIO_new(BIO_s_mem()))) return smime_error_buf;
     378                 :         18 :   BIO_puts(wbio, smime_error_buf);
     379                 :         18 :   ERR_load_crypto_strings();
     380                 :         18 :   ERR_print_errors(wbio);
     381                 :         18 :   BIO_get_mem_data(wbio,&p);
     382                 :         18 :   return p;  /* just leak the wbio */
     383                 :            : }
     384                 :            : 
     385                 :            : /* EOF  -  smimeutil.c */

Generated by: LCOV version 1.9