Back to index

courier  0.68.2
tlspasswordcache.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2003-2007 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #include "config.h"
00007 #include "tlspasswordcache.h"
00008 
00009 #include <stdio.h>
00010 #include <string.h>
00011 #include <stdlib.h>
00012 #include <errno.h>
00013 #include <md5/md5.h>
00014 
00015 #define PASSFILEFORMAT 1
00016 
00017 #if HAVE_OPENSSL097
00018 #include <openssl/ssl.h>
00019 #include <openssl/err.h>
00020 #include <openssl/rand.h>
00021 
00022 static void sslerror(EVP_CIPHER_CTX *ctx, const char *pfix)
00023 {
00024         char errmsg[256];
00025         int errnum=ERR_get_error();
00026  
00027         ERR_error_string_n(errnum, errmsg, sizeof(errmsg)-1);
00028 
00029        fprintf(stderr, "%s: %s\n", pfix, errmsg);
00030 }
00031 
00032 
00033 #endif
00034 
00035 #if HAVE_GCRYPT
00036 
00037 #include <gcrypt.h>
00038 
00039 #define RAND_pseudo_bytes(a,b) (gcry_create_nonce((a),(b)), 0)
00040 
00041 typedef struct {
00042        enum gcry_cipher_algos algo;
00043        enum gcry_cipher_modes mode;
00044 } EVP_CIPHER;
00045 
00046 #define EVP_MAX_IV_LENGTH 256
00047 
00048 const EVP_CIPHER *EVP_des_cbc()
00049 {
00050        static const EVP_CIPHER des_cbc={GCRY_CIPHER_DES,
00051                                     GCRY_CIPHER_MODE_CBC};
00052 
00053        return &des_cbc;
00054 }
00055 
00056 typedef struct {
00057        const EVP_CIPHER *cipher;
00058        gcry_error_t err;
00059        gcry_cipher_hd_t handle;
00060 
00061        int padding;
00062        char *blkbuf;
00063        size_t blksize;
00064 
00065        size_t blkptr;
00066 
00067 } EVP_CIPHER_CTX;
00068 
00069 static void sslerror(EVP_CIPHER_CTX *ctx, const char *pfix)
00070 {
00071        fprintf(stderr, "%s: %s\n", pfix, gcry_strerror(ctx->err));
00072 }
00073 
00074 static void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx)
00075 {
00076        memset(ctx, 0, sizeof(*ctx));
00077 }
00078 
00079 static void EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *ctx)
00080 {
00081        if (ctx->handle)
00082        {
00083               gcry_cipher_close(ctx->handle);
00084               ctx->handle=NULL;
00085        }
00086 
00087        if (ctx->blkbuf)
00088        {
00089               free(ctx->blkbuf);
00090               ctx->blkbuf=NULL;
00091        }
00092 }
00093 
00094 static int EVP_CIPHER_iv_length(const EVP_CIPHER *cipher)
00095 {
00096        size_t l=0;
00097 
00098        gcry_cipher_algo_info(cipher->algo, GCRYCTL_GET_BLKLEN, NULL, &l);
00099        return l;
00100 }
00101 
00102 static int EVP_CIPHER_key_length(const EVP_CIPHER *cipher)
00103 {
00104        size_t l=0;
00105 
00106        gcry_cipher_algo_info(cipher->algo, GCRYCTL_GET_KEYLEN, NULL, &l);
00107        return l;
00108 }
00109 
00110 static int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
00111                            void *impl, unsigned char *key, unsigned char *iv)
00112 {
00113        EVP_CIPHER_CTX_cleanup(ctx);
00114        ctx->cipher=cipher;
00115        ctx->err=gcry_cipher_open(&ctx->handle,
00116                               cipher->algo,
00117                               cipher->mode, 0);
00118 
00119        if (!ctx->err)
00120               ctx->err=gcry_cipher_setkey(ctx->handle, key,
00121                                        EVP_CIPHER_key_length(cipher));
00122 
00123        if (!ctx->err)
00124               ctx->err=gcry_cipher_setiv(ctx->handle, iv,
00125                                       (ctx->blksize=
00126                                        EVP_CIPHER_iv_length(cipher)));
00127 
00128        if (!ctx->err)
00129               if ((ctx->blkbuf=malloc(ctx->blksize)) == NULL)
00130                      ctx->err=gpg_err_code_from_errno(errno);
00131 
00132        ctx->blkptr=0;
00133        ctx->padding=1;
00134 
00135        return ctx->err == 0;
00136 }
00137 
00138 static int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
00139                           int *outl, unsigned char *in, int inl)
00140 {
00141        *outl=0;
00142 
00143        while (inl > 0)
00144        {
00145               size_t cp= (size_t)inl < (ctx->blksize - ctx->blkptr)
00146                      ? (size_t)inl:(ctx->blksize - ctx->blkptr);
00147 
00148               if (ctx->blkptr == 0 && inl > ctx->blksize*2)
00149               {
00150                      cp=(inl / ctx->blksize - 1) * ctx->blksize;
00151 
00152                      if ((ctx->err=gcry_cipher_encrypt(ctx->handle,
00153                                                    out, cp,
00154                                                    in, cp))
00155                          != 0)
00156                             return 0;
00157 
00158                      out += cp;
00159                      *outl += cp;
00160                      in += cp;
00161                      inl -= cp;
00162                      continue;
00163               }
00164 
00165               memcpy(ctx->blkbuf + ctx->blkptr, in, cp);
00166 
00167               in += cp;
00168               inl -= cp;
00169 
00170               ctx->blkptr += cp;
00171 
00172               if (ctx->blkptr == ctx->blksize)
00173               {
00174                      if ((ctx->err=gcry_cipher_encrypt(ctx->handle,
00175                                                    out, ctx->blksize,
00176                                                    ctx->blkbuf,
00177                                                    ctx->blksize)) != 0)
00178                             return 0;
00179                      out += ctx->blksize;
00180                      *outl += ctx->blksize;
00181                      ctx->blkptr=0;
00182               }
00183        }
00184        return 1;
00185 }
00186 
00187 static int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out,
00188                             int *outl)
00189 {
00190        if (ctx->padding)
00191        {
00192               unsigned char pad=ctx->blksize - ctx->blkptr;
00193 
00194               *outl=0;
00195 
00196               if (pad == 0)
00197                      pad=ctx->blksize;
00198 
00199               do
00200               {
00201                      int n_outl;
00202 
00203                      if (!EVP_EncryptUpdate(ctx, out, &n_outl, &pad, 1))
00204                             return 0;
00205                             
00206                      out += n_outl;
00207                      *outl += n_outl;
00208               }
00209               while (ctx->blkptr);
00210        }
00211        else if (ctx->blksize != ctx->blkptr)
00212        {
00213               ctx->err=GPG_ERR_BAD_DATA;
00214               return 0;
00215        }
00216 
00217        return 1;
00218 }
00219 
00220 static int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
00221                            void *impl, unsigned char *key,
00222                            unsigned char *iv)
00223 {
00224        return EVP_EncryptInit_ex(ctx, type, impl, key, iv);
00225 }
00226 
00227 static int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
00228                           int *outl, unsigned char *in, int inl)
00229 {
00230        *outl=0;
00231 
00232        while (inl > 0)
00233        {
00234               size_t cp;
00235 
00236               if (ctx->blkptr == 0 && inl > ctx->blksize * 3)
00237               {
00238                      cp=(inl / ctx->blksize - 2) * ctx->blksize;
00239 
00240                      if ((ctx->err=gcry_cipher_decrypt(ctx->handle,
00241                                                    out, cp,
00242                                                    in, cp))
00243                          != 0)
00244                             return 0;
00245 
00246                      out += cp;
00247                      *outl += cp;
00248                      in += cp;
00249                      inl -= cp;
00250                      continue;
00251               }
00252 
00253               if (ctx->blkptr == ctx->blksize)
00254               {
00255                      if ((ctx->err=gcry_cipher_decrypt(ctx->handle,
00256                                                    out, ctx->blksize,
00257                                                    ctx->blkbuf,
00258                                                    ctx->blksize)) != 0)
00259                             return 0;
00260                      out += ctx->blksize;
00261                      *outl += ctx->blksize;
00262                      ctx->blkptr=0;
00263               }
00264 
00265               cp= (size_t)inl < (ctx->blksize - ctx->blkptr)
00266                      ? (size_t)inl:(ctx->blksize - ctx->blkptr);
00267 
00268               memcpy(ctx->blkbuf + ctx->blkptr, in, cp);
00269 
00270               in += cp;
00271               inl -= cp;
00272 
00273               ctx->blkptr += cp;
00274 
00275        }
00276        return 1;
00277 }
00278 
00279 static int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm,
00280                             int *outl)
00281 {
00282        unsigned char lastval;
00283        int cnt;
00284 
00285        if (ctx->blkptr != ctx->blksize)
00286        {
00287               ctx->err=GPG_ERR_BAD_DATA;
00288               return 0;
00289        }
00290 
00291        if ((ctx->err=gcry_cipher_decrypt(ctx->handle,
00292                                      ctx->blkbuf,
00293                                      ctx->blksize,
00294                                      NULL, 0)) != 0)
00295               return 0;
00296 
00297        if (ctx->padding)
00298        {
00299               lastval=ctx->blkbuf[ctx->blksize-1];
00300 
00301               if (lastval > 0 && lastval <= ctx->blksize)
00302               {
00303                      char n;
00304 
00305                      for (n=0; n<lastval; n++)
00306                             if (ctx->blkbuf[ctx->blksize-1-n] != lastval)
00307                                    lastval=0;
00308               }
00309               else
00310                      lastval=0;
00311 
00312               if (!lastval)
00313               {
00314                      ctx->err=GPG_ERR_BAD_DATA;
00315                      return 0;
00316               }
00317        }
00318        else
00319        {
00320               lastval=0;
00321        }
00322 
00323        cnt=ctx->blksize-lastval;
00324        if (cnt)
00325               memcpy(outm, ctx->blkbuf, cnt);
00326        *outl=cnt;
00327        return 1;
00328 }
00329 
00330 
00331 #define HAVE_OPENSSL097 1
00332 #endif
00333 
00334 #if HAVE_OPENSSL097
00335 
00336 #if BUFSIZ < 8192
00337 #undef BUFSIZ
00338 #define BUFSIZ 8192
00339 #endif
00340 
00341 int tlspassword_init()
00342 {
00343        return 1;
00344 }
00345 
00346 static int save_string(EVP_CIPHER_CTX *,
00347                      const char *, char *,
00348                      int (*)(const char *, size_t, void *),
00349                      void *);
00350 
00351 int tlspassword_save( const char * const *urls,
00352                     const char * const *pwds,
00353                     const char *mpw,
00354                     int (*writefunc)(const char *, size_t, void *),
00355                     void *writefuncarg)
00356 {
00357        char buf[BUFSIZ];
00358        char *p;
00359        int l;
00360        int wl;
00361 
00362        unsigned char iv1_buf[16];
00363        unsigned char iv2_buf[16];
00364        MD5_DIGEST md5_password;
00365        int iv_len, key_len;
00366        EVP_CIPHER_CTX ctx;
00367        const EVP_CIPHER *des=EVP_des_cbc();
00368 
00369        md5_digest(mpw, strlen(mpw), md5_password);
00370 
00371        EVP_CIPHER_CTX_init(&ctx);
00372        iv_len=EVP_CIPHER_iv_length(des);
00373        key_len=EVP_CIPHER_key_length(des);
00374 
00375        if (RAND_pseudo_bytes(iv1_buf, sizeof(iv1_buf)) < 0 ||
00376            RAND_pseudo_bytes(iv2_buf, sizeof(iv2_buf)) < 0)
00377        {
00378               fprintf(stderr,
00379                      "tlspassword_save: internal error - "
00380                      "RAND_pseudo_bytes() failed.\n");
00381               EVP_CIPHER_CTX_cleanup(&ctx);
00382               errno=EIO;
00383               return -1;
00384        }
00385 
00386        if (iv_len + key_len > sizeof(iv1_buf)
00387            || iv_len + key_len != sizeof(iv2_buf)
00388            || key_len != sizeof(md5_password)/2)
00389        {
00390               fprintf(stderr,
00391                      "tlspassword_save: internal error - "
00392                      "unexpected key sizes.\n");
00393               EVP_CIPHER_CTX_cleanup(&ctx);
00394               errno=EIO;
00395               return -1;
00396        }
00397 
00398        p=buf+3;
00399 
00400        if (!EVP_EncryptInit_ex(&ctx, des, NULL,
00401                             (unsigned char *)md5_password,
00402                             iv1_buf) ||
00403            !EVP_EncryptUpdate(&ctx, (unsigned char *)p, &l,
00404                             (unsigned char *)md5_password + key_len,
00405                             sizeof(md5_password)-key_len) ||
00406            !EVP_EncryptUpdate(&ctx, (unsigned char *)(p += l), &l,
00407                             iv2_buf,
00408                             iv_len + key_len) ||
00409            !EVP_EncryptFinal_ex(&ctx, (unsigned char *)(p += l), &l))
00410 
00411        {
00412               sslerror(&ctx, "EVP_EncryptInit_ex");
00413               EVP_CIPHER_CTX_cleanup(&ctx);
00414               errno=EIO;
00415               return -1;
00416        }
00417 
00418        p += l;
00419 
00420        wl= p - buf - 3;
00421 
00422        buf[0]=PASSFILEFORMAT;
00423        buf[1]= wl / 256;
00424        buf[2]= wl % 256;
00425 
00426        l=(*writefunc)(buf, 3, writefuncarg);
00427 
00428        if (l == 0)
00429               l=(*writefunc)((const char *)iv1_buf, iv_len, writefuncarg);
00430 
00431        if (l == 0)
00432               l=(*writefunc)(buf+3, wl, writefuncarg);
00433 
00434        if (l)
00435               return l;
00436 
00437 #if 0
00438        {
00439               int i;
00440 
00441               printf("KEY: ");
00442 
00443               for (i=0; i<key_len + iv_len; i++)
00444                      printf("%02X", (int)(unsigned char)iv2_buf[i]);
00445               printf("\n");
00446        }
00447 #endif
00448 
00449        if (!EVP_EncryptInit_ex(&ctx, des, NULL,
00450                             (unsigned char *)&iv2_buf,
00451                             (unsigned char *)&iv2_buf + key_len))
00452        {
00453               sslerror(&ctx, "EVP_EncryptInit_ex");
00454               EVP_CIPHER_CTX_cleanup(&ctx);
00455               errno=EIO;
00456               return -1;
00457        }
00458 
00459        for (l=0; urls[l]; l++)
00460        {
00461               int n=save_string(&ctx, urls[l], buf, writefunc, writefuncarg);
00462 
00463               if (n)
00464                      return n;
00465 
00466               n=save_string(&ctx, pwds[l], buf, writefunc, writefuncarg);
00467 
00468               if (n)
00469                      return n;
00470        }
00471 
00472        if (!EVP_EncryptFinal_ex(&ctx, (unsigned char *)buf, &l))
00473        {
00474               sslerror(&ctx, "EVP_EncryptInit_ex");
00475               EVP_CIPHER_CTX_cleanup(&ctx);
00476               errno=EIO;
00477               return -1;
00478        }
00479 
00480        if (l)
00481               l=(*writefunc)(buf, l, writefuncarg);
00482 
00483        EVP_CIPHER_CTX_cleanup(&ctx);
00484        return l;
00485 }
00486 
00487 static int save_string(EVP_CIPHER_CTX *ctx,
00488                      const char *str, char *buf,
00489                      int (*writefunc)(const char *, size_t, void *),
00490                      void *writefuncarg)
00491 {
00492        int l;
00493        size_t len=strlen(str);
00494        unsigned char b[2];
00495 
00496        if (len >= 256 * 256)
00497        {
00498               fprintf(stderr,
00499                      "tlspassword_save: internal error - "
00500                      "key sizes too large.\n");
00501               errno=EINVAL;
00502               return -1;
00503        }
00504 
00505        b[0]=len / 256;
00506        b[1]=len % 256;
00507 
00508        if (!EVP_EncryptUpdate(ctx, (unsigned char *)buf, &l, b, 2))
00509        {
00510               sslerror(ctx, "EVP_EncryptUpdate");
00511               return -1;
00512        }
00513 
00514        if (l)
00515        {
00516               l=(*writefunc)(buf, l, writefuncarg);
00517 
00518               if (l)
00519                      return l;
00520        }
00521 
00522        while (len)
00523        {
00524               size_t n=len;
00525 
00526               if (n > BUFSIZ / 4)
00527                      n=BUFSIZ/4;
00528 
00529               if (!EVP_EncryptUpdate(ctx, (unsigned char *)buf, &l,
00530                                    (unsigned char *)str, n))
00531               {
00532                      sslerror(ctx, "EVP_EncryptUpdate");
00533                      return -1;
00534               }
00535 
00536               if (l)
00537               {
00538                      l=(*writefunc)(buf, l, writefuncarg);
00539 
00540                      if (l)
00541                             return l;
00542               }
00543 
00544               str += n;
00545               len -= n;
00546        }
00547 
00548        return 0;
00549 }
00550 
00551 struct tempstring_list {
00552        struct tempstring_list *next;
00553        char *url;
00554        char *pw;
00555 };
00556 
00557 struct tlspassword_readinfo {
00558        char buf[BUFSIZ / 2];
00559        char *bufptr;
00560        size_t bufleft;
00561 
00562        int (*readfunc)(char *, size_t, void *);
00563        void *readfuncarg;
00564 
00565        struct tempstring_list *tl_list, *tl_last;
00566 
00567        int (*readhandler)(struct tlspassword_readinfo *, char *, int);
00568 
00569        unsigned int stringhi;
00570        char *stringptr;
00571        size_t stringleft;
00572        size_t nstrings;
00573 };
00574 
00575 
00576 static int tlspassword_read(struct tlspassword_readinfo *p,
00577                          char *buf,
00578                          size_t nbytes)
00579 {
00580        while (nbytes)
00581        {
00582               size_t c;
00583 
00584               if (p->bufleft == 0)
00585               {
00586                      int n= (*p->readfunc)(p->buf, sizeof(p->buf),
00587                                          p->readfuncarg);
00588 
00589                      if (n <= 0)
00590                             return -1;
00591                      p->bufptr=p->buf;
00592                      p->bufleft=n;
00593               }
00594 
00595               c=nbytes;
00596 
00597               if (c > p->bufleft)
00598                      c=p->bufleft;
00599 
00600               memcpy(buf, p->bufptr, c);
00601               p->bufptr += c;
00602               p->bufleft -= c;
00603               nbytes -= c;
00604        }
00605 
00606        return 0;
00607 }
00608 
00609 static void tlspassword_readcleanup(struct tlspassword_readinfo *p)
00610 {
00611        while (p->tl_list)
00612        {
00613               struct tempstring_list *t=p->tl_list;
00614 
00615               p->tl_list=t->next;
00616               if (t->url)
00617                      free(t->url);
00618               if (t->pw)
00619                      free(t->pw);
00620               free(t);
00621        }
00622 }
00623 
00624 static int read_stringhi(struct tlspassword_readinfo *, char *, int);
00625 
00626 int tlspassword_load( int (*callback)(char *, size_t, void *),
00627                     void *callback_arg,
00628 
00629                     const char *mpw,
00630 
00631                     void (*readfunc)(const char * const *,
00632                                    const char * const *,
00633                                    void *),
00634                     void *readfunc_arg)
00635 {
00636        char buf[BUFSIZ];
00637        int outl;
00638        char *p;
00639 
00640        MD5_DIGEST md5_password;
00641        int iv_len, key_len;
00642        EVP_CIPHER_CTX ctx;
00643        const EVP_CIPHER *des=EVP_des_cbc();
00644        struct tlspassword_readinfo readinfo;
00645        char header[3];
00646        size_t l;
00647        char iv1_buf[EVP_MAX_IV_LENGTH];
00648        struct tempstring_list *tl;
00649        const char **urls, **pws;
00650 
00651        readinfo.bufleft=0;
00652        readinfo.readfunc=callback;
00653        readinfo.readfuncarg=callback_arg;
00654        readinfo.tl_list=NULL;
00655        readinfo.tl_last=NULL;
00656 
00657        md5_digest(mpw, strlen(mpw), md5_password);
00658 
00659        EVP_CIPHER_CTX_init(&ctx);
00660        iv_len=EVP_CIPHER_iv_length(des);
00661        key_len=EVP_CIPHER_key_length(des);
00662 
00663        if (tlspassword_read(&readinfo, header, 3) ||
00664            tlspassword_read(&readinfo, iv1_buf, iv_len))
00665        {
00666               EVP_CIPHER_CTX_cleanup(&ctx);
00667               return -1;
00668        }
00669        if (header[0] != PASSFILEFORMAT)
00670        {
00671               errno=EINVAL;
00672               EVP_CIPHER_CTX_cleanup(&ctx);
00673               return -1;
00674        }
00675 
00676        if ((l=(size_t)(unsigned char)header[1] * 256
00677             + (unsigned char)header[2]) > sizeof(buf) / 4)
00678        {
00679               errno=EINVAL;
00680               EVP_CIPHER_CTX_cleanup(&ctx);
00681               return -1;
00682        }
00683 
00684        if (tlspassword_read(&readinfo, buf, l))
00685               return -1;
00686 
00687        p=buf + sizeof(buf)/2;
00688        if (!EVP_DecryptInit_ex(&ctx, des, NULL,
00689                             (unsigned char *)md5_password,
00690                             (unsigned char *)&iv1_buf) ||
00691            !EVP_DecryptUpdate(&ctx, (unsigned char *)p, &outl,
00692                             (unsigned char *)buf, l) ||
00693            !EVP_DecryptFinal_ex(&ctx, (unsigned char *)(p += outl), &outl))
00694        {
00695               errno=EINVAL;
00696               EVP_CIPHER_CTX_cleanup(&ctx);
00697               return -1;
00698        }
00699 
00700        p += outl;
00701 
00702        if (p - (buf +sizeof(buf)/2) != sizeof(md5_password) + iv_len
00703            || memcmp(buf + sizeof(buf)/2, (char *)(&md5_password) + key_len,
00704                     sizeof(md5_password)-key_len))
00705        {
00706               errno=EINVAL;
00707               EVP_CIPHER_CTX_cleanup(&ctx);
00708               return -1;
00709        }
00710 
00711 #if 0
00712        {
00713               int i;
00714 
00715               printf("KEY: ");
00716 
00717               for (i=0; i<key_len + iv_len; i++)
00718                      printf("%02X", (int)(unsigned char)(p-iv_len-key_len)[i]);
00719               printf("\n");
00720        }
00721 #endif
00722 
00723        if (!EVP_DecryptInit_ex(&ctx, des, NULL,
00724                             (unsigned char *)(p-iv_len-key_len),
00725                             (unsigned char *)(p-iv_len)))
00726        {
00727               errno=EINVAL;
00728               EVP_CIPHER_CTX_cleanup(&ctx);
00729               return -1;
00730        }
00731 
00732        readinfo.nstrings=0;
00733        readinfo.readhandler= &read_stringhi;
00734        for (;;)
00735        {
00736               if (readinfo.bufleft == 0)
00737               {
00738                      outl= (*readinfo.readfunc)(readinfo.buf,
00739                                              sizeof(readinfo.buf),
00740                                              readinfo.readfuncarg);
00741 
00742                      if (outl == 0)
00743                             break;
00744 
00745                      if (outl < 0)
00746                      {
00747                             tlspassword_readcleanup(&readinfo);
00748                             errno=EINVAL;
00749                             EVP_CIPHER_CTX_cleanup(&ctx);
00750                             return -1;
00751                      }
00752 
00753                      readinfo.bufptr=readinfo.buf;
00754                      readinfo.bufleft=outl;
00755               }
00756 
00757               if (!EVP_DecryptUpdate(&ctx, (unsigned char *)buf, &outl,
00758                                    (unsigned char *)
00759                                    readinfo.bufptr, readinfo.bufleft))
00760               {
00761                      tlspassword_readcleanup(&readinfo);
00762                      errno=EINVAL;
00763                      EVP_CIPHER_CTX_cleanup(&ctx);
00764                      return -1;
00765               }
00766               readinfo.bufleft=0;
00767 
00768               p=buf;
00769               while (outl)
00770               {
00771                      int n= (*readinfo.readhandler)(&readinfo, p, outl);
00772 
00773                      if (n < 0)
00774                      {
00775                             tlspassword_readcleanup(&readinfo);
00776                             EVP_CIPHER_CTX_cleanup(&ctx);
00777                             return -1;
00778                      }
00779 
00780                      p += n;
00781                      outl -= n;
00782               }
00783        }
00784 
00785        if (!EVP_DecryptFinal_ex(&ctx, (unsigned char *)buf, &outl))
00786        {
00787               tlspassword_readcleanup(&readinfo);
00788               errno=EINVAL;
00789               EVP_CIPHER_CTX_cleanup(&ctx);
00790               return -1;
00791        }
00792 
00793        p=buf;
00794        while (outl)
00795        {
00796               int n= (*readinfo.readhandler)(&readinfo, p, outl);
00797 
00798               if (n < 0)
00799               {
00800                      tlspassword_readcleanup(&readinfo);
00801                      errno=EINVAL;
00802                      EVP_CIPHER_CTX_cleanup(&ctx);
00803                      return -1;
00804               }
00805 
00806               p += n;
00807               outl -= n;
00808        }
00809 
00810        if (readinfo.tl_list && readinfo.tl_list->pw == NULL)
00811               /* Odd # of strings -- no good */
00812        {
00813               tlspassword_readcleanup(&readinfo);
00814               errno=EINVAL;
00815               EVP_CIPHER_CTX_cleanup(&ctx);
00816               return (-1);
00817        }
00818 
00819        if ((urls=malloc((readinfo.nstrings+1) * sizeof(char *))) == NULL ||
00820            (pws=malloc((readinfo.nstrings+1) * sizeof(char *))) == NULL)
00821        {
00822               if (urls)
00823                      free(urls);
00824 
00825               tlspassword_readcleanup(&readinfo);
00826               EVP_CIPHER_CTX_cleanup(&ctx);
00827               return (-1);
00828        }
00829 
00830        l=0;
00831        for (tl=readinfo.tl_list; tl; tl=tl->next)
00832        {
00833               urls[l]=tl->url;
00834               pws[l]=tl->pw;
00835               l++;
00836        }
00837 
00838        urls[l]=NULL;
00839        pws[l]=NULL;
00840 
00841        (*readfunc)(urls, pws, readfunc_arg);
00842 
00843        free(urls);
00844        free(pws);
00845 
00846        tlspassword_readcleanup(&readinfo);
00847        EVP_CIPHER_CTX_cleanup(&ctx);
00848        return 0;
00849 }
00850 
00851 static int read_stringlo(struct tlspassword_readinfo *info,
00852                       char *p, int n);
00853 
00854 static int read_string(struct tlspassword_readinfo *info,
00855                      char *p, int n);
00856 
00857 static int read_stringhi(struct tlspassword_readinfo *info,
00858                       char *p, int n)
00859 {
00860        info->stringhi=(unsigned char)*p;
00861        info->stringhi *= 256;
00862 
00863        info->readhandler=read_stringlo;
00864        return 1;
00865 }
00866 
00867 static int read_stringlo(struct tlspassword_readinfo *info,
00868                       char *p, int n)
00869 {
00870        struct tempstring_list *t;
00871 
00872        info->readhandler=read_string;
00873        info->stringleft=info->stringhi + (unsigned char)*p;
00874 
00875        if (info->tl_last &&
00876            info->tl_last->pw == NULL) /* This string is the pw */
00877        {
00878               info->tl_last->pw=malloc(info->stringleft+1);
00879               if (!info->tl_last->pw)
00880                      return -1;
00881 
00882               info->stringptr=info->tl_last->pw;
00883               return 1;
00884        }
00885 
00886        if ((t=(struct tempstring_list *)malloc(sizeof(struct tempstring_list))
00887             ) == NULL || (t->url=malloc(info->stringleft+1)) == NULL)
00888        {
00889               if (t) free(t);
00890               return -1;
00891        }
00892 
00893        if (info->tl_last)
00894               info->tl_last->next=t;
00895        else
00896               info->tl_list=t;
00897        info->tl_last=t;
00898        info->stringptr=t->url;
00899        t->next=NULL;
00900        t->pw=NULL;
00901        ++info->nstrings;
00902        return 1;
00903 }
00904 
00905 static int read_string(struct tlspassword_readinfo *info, char *p, int n)
00906 {
00907        if (n > info->stringleft)
00908               n=info->stringleft;
00909 
00910        memcpy(info->stringptr, p, n);
00911        info->stringptr += n;
00912        info->stringleft -= n;
00913 
00914        if (info->stringleft == 0)
00915        {
00916               info->readhandler=read_stringhi;
00917               *info->stringptr=0;
00918        }
00919 
00920        return n;
00921 }
00922 
00923 #else
00924 
00925 
00926 int tlspassword_init()
00927 {
00928        return 0;
00929 }
00930 
00931 
00932 int tlspassword_save( const char * const *urls,
00933                     const char * const *pwds,
00934                     const char *mpw,
00935                     int (*writefunc)(const char *, size_t, void *),
00936                     void *writefuncarg)
00937 {
00938        errno=EIO;
00939        return -1;
00940 }
00941 
00942 int tlspassword_load( int (*readfunc)(char *, size_t, void *),
00943                     void *readfuncarg,
00944 
00945                     const char *mpw,
00946                     void (*callback)(const char * const *,
00947                                    const char * const *,
00948                                    void *),
00949                     void *callback_arg)
00950 {
00951        errno=EIO;
00952        return -1;
00953 }
00954 #endif