* Create help for explaining how encrypted password file support
[alpine.git] / pith / smkeys.c
blob56103e91f52f3cddb1aba4b7553855a96ba82a9a
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: smkeys.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2013-2014 Eduardo Chappa
8 * Copyright 2008 University of Washington
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
20 * This is based on a contribution from Jonathan Paisley, see smime.c
24 #include "../pith/headers.h"
26 #ifdef SMIME
28 #include "../pith/status.h"
29 #include "../pith/conf.h"
30 #include "../pith/remote.h"
31 #include "../pith/tempfile.h"
32 #include "../pith/busy.h"
33 #include "../pith/osdep/lstcmpnt.h"
34 #include "../pith/util.h"
35 #include "smkeys.h"
37 #ifdef APPLEKEYCHAIN
38 #include <Security/SecKeychain.h>
39 #include <Security/SecKeychainItem.h>
40 #include <Security/SecKeychainSearch.h>
41 #include <Security/SecCertificate.h>
42 #endif /* APPLEKEYCHAIN */
45 /* internal prototypes */
46 static char *emailstrclean(char *string);
47 static int mem_add_extra_cacerts(char *contents, X509_LOOKUP *lookup);
49 void
50 get_fingerprint(X509 *cert, const EVP_MD *type, char *buf, size_t maxLen)
52 unsigned char md[128];
53 char *b;
54 unsigned int len, i;
56 len = sizeof(md);
58 X509_digest(cert, type, md, &len);
60 b = buf;
61 *b = 0;
62 for(i=0; i<len; i++){
63 if(b-buf+3>=maxLen)
64 break;
66 if(i != 0)
67 *b++ = ':';
69 snprintf(b, maxLen - (b-buf), "%02x", md[i]);
70 b+=2;
76 * Remove leading whitespace, trailing whitespace and convert
77 * to lowercase. Also remove slash characters
79 * Args: s, -- The string to clean
81 * Result: the cleaned string
83 static char *
84 emailstrclean(char *string)
86 char *s = string, *sc = NULL, *p = NULL;
88 for(; *s; s++){ /* single pass */
89 if(!isspace((unsigned char) (*s))){
90 p = NULL; /* not start of blanks */
91 if(!sc) /* first non-blank? */
92 sc = string; /* start copying */
94 else if(!p) /* it's OK if sc == NULL */
95 p = sc; /* start of blanks? */
97 if(sc && *s!='/' && *s!='\\') /* if copying, copy */
98 *sc++ = isupper((unsigned char) (*s))
99 ? (unsigned char) tolower((unsigned char) (*s))
100 : (unsigned char) (*s);
103 if(p) /* if ending blanks */
104 *p = '\0'; /* tie off beginning */
105 else if(!sc) /* never saw a non-blank */
106 *string = '\0'; /* so tie whole thing off */
108 return(string);
113 * Add a lookup for each "*.crt" file in the given directory.
116 add_certs_in_dir(X509_LOOKUP *lookup, char *path, char *ext, CertList **cdata)
118 char buf[MAXPATH];
119 struct direct *d;
120 DIR *dirp;
121 CertList *cert, *cl;
122 int ret = 0;
124 if((dirp = opendir(path)) != NULL){
125 while(!ret && (d=readdir(dirp)) != NULL){
126 if(srchrstr(d->d_name, ext)){
127 build_path(buf, path, d->d_name, sizeof(buf));
129 if(!X509_LOOKUP_load_file(lookup, buf, X509_FILETYPE_PEM)){
130 q_status_message1(SM_ORDER, 3, 3, _("Error loading file %s"), buf);
131 ret = -1;
132 } else {
133 if(cdata){
134 cert = fs_get(sizeof(CertList));
135 memset((void *)cert, 0, sizeof(CertList));
136 cert->name = cpystr(d->d_name);
137 if(*cdata == NULL)
138 *cdata = cert;
139 else{
140 for (cl = *cdata; cl && cl->next; cl = cl->next);
141 cl->next = cert;
150 closedir(dirp);
153 return ret;
158 * Get an X509_STORE. This consists of the system
159 * certs directory and any certificates in the user's
160 * ~/.alpine-smime/ca directory.
162 X509_STORE *
163 get_ca_store(void)
165 X509_LOOKUP *lookup;
166 X509_STORE *store = NULL;
168 dprint((9, "get_ca_store()"));
170 if(!(store=X509_STORE_new())){
171 dprint((9, "X509_STORE_new() failed"));
172 return store;
175 if(!(lookup=X509_STORE_add_lookup(store, X509_LOOKUP_file()))){
176 dprint((9, "X509_STORE_add_lookup() failed"));
177 X509_STORE_free(store);
178 return NULL;
181 if(ps_global->smime && ps_global->smime->catype == Container
182 && ps_global->smime->cacontent){
184 if(!mem_add_extra_cacerts(ps_global->smime->cacontent, lookup)){
185 X509_STORE_free(store);
186 return NULL;
189 else if(ps_global->smime && ps_global->smime->catype == Directory
190 && ps_global->smime->capath){
191 if(add_certs_in_dir(lookup, ps_global->smime->capath, ".crt", &ps_global->smime->cacertlist) < 0){
192 X509_STORE_free(store);
193 return NULL;
197 if(!(lookup=X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()))){
198 X509_STORE_free(store);
199 return NULL;
202 #ifdef SMIME_SSLCERTS
203 dprint((9, "get_ca_store(): adding cacerts from %s", SMIME_SSLCERTS));
204 X509_LOOKUP_add_dir(lookup, SMIME_SSLCERTS, X509_FILETYPE_PEM);
205 #endif
207 return store;
211 EVP_PKEY *
212 load_key(PERSONAL_CERT *pc, char *pass)
214 BIO *in;
215 EVP_PKEY *key = NULL;
216 char buf[MAXPATH], file[MAXPATH];
218 if(!(ps_global->smime && pc && pc->name))
219 return key;
221 if(ps_global->smime->privatetype == Container){
222 char *q;
224 if(pc->keytext && (q = strstr(pc->keytext, "-----END")) != NULL){
225 while(*q && *q != '\n')
226 q++;
228 if(*q == '\n')
229 q++;
231 if((in = BIO_new_mem_buf(pc->keytext, q-pc->keytext)) != NULL){
232 key = PEM_read_bio_PrivateKey(in, NULL, NULL, pass);
233 BIO_free(in);
237 else if(ps_global->smime->privatetype == Directory){
238 /* filename is path/name.key */
239 strncpy(buf, pc->name, sizeof(buf)-5);
240 buf[sizeof(buf)-5] = '\0';
241 strncat(buf, ".key", 5);
242 build_path(file, ps_global->smime->privatepath, buf, sizeof(file));
244 if(!(in = BIO_new_file(file, "r")))
245 return NULL;
247 key = PEM_read_bio_PrivateKey(in, NULL, NULL, pass);
248 BIO_free(in);
251 return key;
255 #ifdef notdef
256 static char *
257 get_x509_name_entry(const char *key, X509_NAME *name)
259 int i, c, n;
260 char buf[256];
261 char *id;
263 if(!name)
264 return NULL;
266 c = X509_NAME_entry_count(name);
268 for(i=0; i<c; i++){
269 X509_NAME_ENTRY *e;
271 e = X509_NAME_get_entry(name, i);
272 if(!e)
273 continue;
275 buf[0] = 0;
276 id = buf;
278 n = OBJ_obj2nid(e->object);
279 if((n == NID_undef) || ((id=(char*) OBJ_nid2sn(n)) == NULL)){
280 i2t_ASN1_OBJECT(buf, sizeof(buf), e->object);
281 id = buf;
284 if((strucmp(id, "email")==0) || (strucmp(id, "emailAddress")==0)){
285 X509_NAME_get_text_by_OBJ(name, e->object, buf, sizeof(buf)-1);
286 return cpystr(buf);
290 return NULL;
294 char *
295 get_x509_subject_email(X509 *x)
297 char* result;
298 result = get_x509_name_entry("email", X509_get_subject_name(x));
299 if( !result ){
300 result = get_x509_name_entry("emailAddress", X509_get_subject_name(x));
303 return result;
305 #endif /* notdef */
307 #include <openssl/x509v3.h>
309 * This newer version is from Adrian Vogel. It looks for the email
310 * address not only in the email address field, but also in an
311 * X509v3 extension field, Subject Altenative Name.
313 char **
314 get_x509_subject_email(X509 *x)
316 char **result = NULL;
317 int i, n;
318 STACK_OF(OPENSSL_STRING) *emails = X509_get1_email(x);
319 if ((n = sk_OPENSSL_STRING_num(emails)) > 0) {
320 result = fs_get((n+1)*sizeof(char *));
321 for(i = 0; i < n; i++)
322 result[i] = cpystr(sk_OPENSSL_STRING_value(emails, i));
323 result[i] = NULL;
325 X509_email_free(emails);
326 return result;
331 * Save the certificate for the given email address in
332 * ~/.alpine-smime/public.
334 * Should consider the security hazards in making a file with
335 * the email address that has come from the certificate.
337 * The argument email is destroyed.
339 * args: ctype says where the user wants to save the certificate
341 void
342 save_cert_for(char *email, X509 *cert, WhichCerts ctype)
344 if(!ps_global->smime || ctype == Private)
345 return;
347 dprint((9, "save_cert_for(%s, %s)", email ? email : "?", ctype == Public ? _("Public") : ctype == Private ? _("Private") : "CACert"));
348 emailstrclean(email);
350 if(ps_global->smime->publictype == Keychain){
351 #ifdef APPLEKEYCHAIN
353 OSStatus rc;
354 SecCertificateRef secCertificateRef;
355 CSSM_DATA certData;
357 memset((void *) &certData, 0, sizeof(certData));
358 memset((void *) &secCertificateRef, 0, sizeof(secCertificateRef));
360 /* convert OpenSSL X509 cert data to MacOS certData */
361 if((certData.Length = i2d_X509(cert, &(certData.Data))) > 0){
364 * Put that certData into a SecCertificateRef.
365 * Version 3 should work for versions 1-3.
367 if(!(rc=SecCertificateCreateFromData(&certData,
368 CSSM_CERT_X_509v3,
369 CSSM_CERT_ENCODING_DER,
370 &secCertificateRef))){
372 /* add it to the default keychain */
373 if(!(rc=SecCertificateAddToKeychain(secCertificateRef, NULL))){
374 /* ok */
376 else if(rc == errSecDuplicateItem){
377 dprint((9, "save_cert_for: certificate for %s already in keychain", email));
379 else{
380 dprint((9, "SecCertificateAddToKeychain failed"));
383 else{
384 dprint((9, "SecCertificateCreateFromData failed"));
387 else{
388 dprint((9, "i2d_X509 failed"));
391 #endif /* APPLEKEYCHAIN */
393 else if(SMHOLDERTYPE(ctype) == Container){
394 REMDATA_S *rd = NULL;
395 char path[MAXPATH];
396 char *upath = PATHCERTDIR(ctype);
397 char *tempfile = NULL;
398 int err = 0;
399 CertList *clist = DATACERT(ctype);
401 add_to_end_of_certlist(&clist, email, X509_dup(cert));
403 switch(ctype){
404 case Private: ps_global->smime->privatecertlist = clist; break;
405 case Public : ps_global->smime->publiccertlist = clist; break;
406 case CACert : ps_global->smime->cacertlist = clist; break;
407 default: break;
410 if(!upath)
411 return;
413 if(IS_REMOTE(upath)){
414 rd = rd_create_remote(RemImap, upath, REMOTE_SMIME_SUBTYPE,
415 NULL, "Error: ",
416 _("Can't access remote smime configuration."));
417 if(!rd){
418 return;
421 (void) rd_read_metadata(rd);
423 if(rd->access == MaybeRorW){
424 if(rd->read_status == 'R')
425 rd->access = ReadOnly;
426 else
427 rd->access = ReadWrite;
430 if(rd->access != NoExists){
432 rd_check_remvalid(rd, 1L);
435 * If the cached info says it is readonly but
436 * it looks like it's been fixed now, change it to readwrite.
438 if(rd->read_status == 'R'){
439 rd_check_readonly_access(rd);
440 if(rd->read_status == 'W'){
441 rd->access = ReadWrite;
442 rd->flags |= REM_OUTOFDATE;
444 else
445 rd->access = ReadOnly;
449 if(rd->flags & REM_OUTOFDATE){
450 if(rd_update_local(rd) != 0){
452 dprint((1, "save_cert_for: rd_update_local failed\n"));
453 rd_close_remdata(&rd);
454 return;
457 else
458 rd_open_remote(rd);
460 if(rd->access != ReadWrite || rd_remote_is_readonly(rd)){
461 rd_close_remdata(&rd);
462 return;
465 rd->flags |= DO_REMTRIM;
467 strncpy(path, rd->lf, sizeof(path)-1);
468 path[sizeof(path)-1] = '\0';
470 else{
471 strncpy(path, upath, sizeof(path)-1);
472 path[sizeof(path)-1] = '\0';
475 tempfile = tempfile_in_same_dir(path, "az", NULL);
476 if(tempfile){
477 if(certlist_to_file(tempfile, DATACERT(ctype)))
478 err++;
480 if(!err){
481 if(rename_file(tempfile, path) < 0){
482 q_status_message2(SM_ORDER, 3, 3,
483 _("Can't rename %s to %s"), tempfile, path);
484 err++;
488 if(!err && IS_REMOTE(upath)){
489 int e, we_cancel;
490 char datebuf[200];
492 datebuf[0] = '\0';
494 we_cancel = busy_cue(_("Copying to remote smime container"), NULL, 1);
495 if((e = rd_update_remote(rd, datebuf)) != 0){
496 if(e == -1){
497 q_status_message2(SM_ORDER | SM_DING, 3, 5,
498 _("Error opening temporary smime file %s: %s"),
499 rd->lf, error_description(errno));
500 dprint((1,
501 "write_remote_smime: error opening temp file %s\n",
502 rd->lf ? rd->lf : "?"));
504 else{
505 q_status_message2(SM_ORDER | SM_DING, 3, 5,
506 _("Error copying to %s: %s"),
507 rd->rn, error_description(errno));
508 dprint((1,
509 "write_remote_smime: error copying from %s to %s\n",
510 rd->lf ? rd->lf : "?", rd->rn ? rd->rn : "?"));
513 q_status_message(SM_ORDER | SM_DING, 5, 5,
514 _("Copy of smime cert to remote folder failed, changes NOT saved remotely"));
516 else{
517 rd_update_metadata(rd, datebuf);
518 rd->read_status = 'W';
521 rd_close_remdata(&rd);
523 if(we_cancel)
524 cancel_busy_cue(-1);
527 fs_give((void **) &tempfile);
530 else if(SMHOLDERTYPE(ctype) == Directory){
531 char *path = PATHCERTDIR(ctype);
532 char certfilename[MAXPATH];
533 BIO *bio_out;
535 build_path(certfilename, path, email, sizeof(certfilename));
536 strncat(certfilename, ".crt", sizeof(certfilename)-1-strlen(certfilename));
537 certfilename[sizeof(certfilename)-1] = 0;
539 bio_out = BIO_new_file(certfilename, "w");
540 if(bio_out){
541 PEM_write_bio_X509(bio_out, cert);
542 BIO_free(bio_out);
543 q_status_message1(SM_ORDER, 1, 1, _("Saved certificate for <%s>"), email);
545 else{
546 q_status_message1(SM_ORDER, 1, 1, _("Couldn't save certificate for <%s>"), email);
553 * Try to retrieve the certificate for the given email address.
554 * The caller should free the cert.
556 X509 *
557 get_cert_for(char *email, WhichCerts ctype)
559 char certfilename[MAXPATH];
560 char emailaddr[MAXPATH];
561 X509 *cert = NULL;
562 BIO *in;
564 if(!ps_global->smime)
565 return cert;
567 dprint((9, "get_cert_for(%s, %s)", email ? email : "?", "none yet"));
569 if(ctype == Private) /* there is no private certificate info */
570 ctype = Public; /* return public information instead */
571 strncpy(emailaddr, email, sizeof(emailaddr)-1);
572 emailaddr[sizeof(emailaddr)-1] = 0;
574 /* clean it up (lowercase, space removal) */
575 emailstrclean(emailaddr);
577 if(ps_global->smime->publictype == Keychain){
578 #ifdef APPLEKEYCHAIN
580 OSStatus rc;
581 SecKeychainItemRef itemRef = nil;
582 SecKeychainAttributeList attrList;
583 SecKeychainAttribute attrib;
584 SecKeychainSearchRef searchRef = nil;
585 CSSM_DATA certData;
587 /* low-level form of MacOS data */
588 memset((void *) &certData, 0, sizeof(certData));
590 attrList.count = 1;
591 attrList.attr = &attrib;
593 /* kSecAlias means email address for a certificate */
594 attrib.tag = kSecAlias;
595 attrib.data = emailaddr;
596 attrib.length = strlen(attrib.data);
598 /* Find the certificate in the default keychain */
599 if(!(rc=SecKeychainSearchCreateFromAttributes(NULL,
600 kSecCertificateItemClass,
601 &attrList,
602 &searchRef))){
604 if(!(rc=SecKeychainSearchCopyNext(searchRef, &itemRef))){
606 /* extract the data portion of the certificate */
607 if(!(rc=SecCertificateGetData((SecCertificateRef) itemRef, &certData))){
610 * Convert it from MacOS form to OpenSSL form.
611 * The input is certData from above and the output
612 * is the X509 *cert.
614 if(!d2i_X509(&cert, &(certData.Data), certData.Length)){
615 dprint((9, "d2i_X509 failed"));
618 else{
619 dprint((9, "SecCertificateGetData failed"));
622 else if(rc == errSecItemNotFound){
623 dprint((9, "get_cert_for: Public cert for %s not found", emailaddr));
625 else{
626 dprint((9, "SecKeychainSearchCopyNext failed"));
629 else{
630 dprint((9, "SecKeychainSearchCreateFromAttributes failed"));
633 if(searchRef)
634 CFRelease(searchRef);
636 #endif /* APPLEKEYCHAIN */
638 else if(SMHOLDERTYPE(ctype) == Container){
639 CertList *cl;
641 for(cl = DATACERT(ctype); cl; cl = cl->next){
642 if(cl->name && !strucmp(emailaddr, cl->name))
643 break;
646 if(cl)
647 cert = X509_dup((X509 *) cl->x509_cert);
649 else if(SMHOLDERTYPE(ctype) == Directory){
650 build_path(certfilename, PATHCERTDIR(ctype), emailaddr, sizeof(certfilename));
651 strncat(certfilename, EXTCERT(ctype), sizeof(certfilename)-1-strlen(certfilename));
652 certfilename[sizeof(certfilename)-1] = 0;
654 if((in = BIO_new_file(certfilename, "r"))!=0){
656 cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
658 if(cert){
659 /* could check email addr in cert matches */
662 BIO_free(in);
666 return cert;
670 * load_cert_for_key finds a certificate in pathdir that matches a private key
671 * pkey. It returns its name in certfile, and the certificate in *pcert.
672 * return value: success: different from zero, failure 0. If both certfile
673 * and pcert are NULL, this function returns if there is certificate that
674 * matches the given key.
677 load_cert_for_key(char *pathdir, EVP_PKEY *pkey, char **certfile, X509 **pcert)
679 DIR *dirp;
680 struct dirent *d;
681 int rv = 0;
682 BIO *in;
683 X509 *x;
684 char buf[MAXPATH+1], pathcert[MAXPATH+1];
686 if(pathdir == NULL || pkey == NULL)
687 return 0;
689 if(certfile) *certfile = NULL;
690 if(pcert) *pcert = NULL;
692 if((dirp = opendir(pathdir)) != NULL){
693 while(rv == 0 && (d=readdir(dirp)) != NULL){
694 size_t ll;
696 if((ll=strlen(d->d_name)) && ll > 4){
697 if(!strcmp(d->d_name+ll-4, ".crt")){
698 strncpy(buf, d->d_name, sizeof(buf));
699 buf[sizeof(buf)-1] = '\0';
700 build_path(pathcert, pathdir, buf, sizeof(pathcert));
701 if((in = BIO_new_file(pathcert, "r")) != NULL){
702 if((x = PEM_read_bio_X509(in, NULL, NULL, NULL)) != NULL){
703 if(X509_check_private_key(x, pkey) > 0){
704 rv = 1;
705 if(certfile) *certfile = cpystr(buf);
706 if(pcert) *pcert = x;
708 else
709 X509_free(x);
711 BIO_free(in);
716 closedir(dirp);
718 return rv;
722 PERSONAL_CERT *
723 mem_to_personal_certs(char *contents)
725 PERSONAL_CERT *result = NULL;
726 char *p, *q, *line, *name, *keytext, *save_p;
727 X509 *cert = NULL;
729 if(contents && *contents){
730 for(p = contents; *p != '\0';){
731 line = p;
733 while(*p && *p != '\n')
734 p++;
736 save_p = NULL;
737 if(*p == '\n'){
738 save_p = p;
739 *p++ = '\0';
742 if(strncmp(EMAILADDRLEADER, line, strlen(EMAILADDRLEADER)) == 0){
743 name = line + strlen(EMAILADDRLEADER);
744 cert = get_cert_for(name, Public);
745 keytext = p;
747 /* advance p past this record */
748 if((q = strstr(keytext, "-----END")) != NULL){
749 while(*q && *q != '\n')
750 q++;
752 if(*q == '\n')
753 q++;
755 p = q;
757 else{
758 p = p + strlen(p);
759 q_status_message(SM_ORDER | SM_DING, 3, 3, _("Error in privatekey container, missing END"));
762 if(cert){
763 PERSONAL_CERT *pc;
765 pc = (PERSONAL_CERT *) fs_get(sizeof(*pc));
766 pc->cert = cert;
767 pc->name = cpystr(name);
768 pc->keytext = keytext; /* a pointer into contents */
770 pc->key = load_key(pc, "");
772 pc->next = result;
773 result = pc;
777 if(save_p)
778 *save_p = '\n';
782 return result;
786 CertList *
787 mem_to_certlist(char *contents, WhichCerts ctype)
789 CertList *ret = NULL;
790 char *p, *q, *line, *name, *certtext, *save_p;
791 X509 *cert = NULL;
792 BIO *in;
793 char *sep = (ctype == Public || ctype == Private)
794 ? EMAILADDRLEADER : CACERTSTORELEADER;
796 if(contents && *contents){
797 for(p = contents; *p != '\0';){
798 line = p;
800 while(*p && *p != '\n')
801 p++;
803 save_p = NULL;
804 if(*p == '\n'){
805 save_p = p;
806 *p++ = '\0';
809 if(strncmp(sep, line, strlen(sep)) == 0){
810 name = line + strlen(sep);
811 cert = NULL;
812 certtext = strstr(p, "-----BEGIN");
813 if(certtext != NULL){
814 if((q = strstr(certtext, sep)) != NULL)
815 p = q;
816 else
817 p = q = certtext+strlen(certtext);
819 if((in = BIO_new_mem_buf(certtext, q-certtext)) != 0){
820 cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
821 BIO_free(in);
824 else{
825 q_status_message2(SM_ORDER | SM_DING, 3, 3, _("Error in %scert container, missing BEGIN, certtext=%s"), ctype == Public ? _("public") : _("ca"), p);
826 p = p + strlen(p);
829 if(name && cert)
830 add_to_end_of_certlist(&ret, name, cert);
833 if(save_p)
834 *save_p = '\n';
838 return ret;
843 * Add the CACert Container contents into the CACert store.
845 * Returns > 0 for success, 0 for failure
848 mem_add_extra_cacerts(char *contents, X509_LOOKUP *lookup)
850 char *p, *q, *line, *certtext, *save_p;
851 BIO *in, *out;
852 int len, failed = 0;
853 char *tempfile;
854 char iobuf[4096];
857 * The most straight-forward way to do this is to write
858 * the container contents to a temp file and then load the
859 * contents of the file with X509_LOOKUP_load_file(), like
860 * is done in add_certs_in_dir(). What we don't know is if
861 * each file should consist of one cacert or if they can all
862 * just be jammed together into one file. To be safe, we'll use
863 * one file per and do each in a separate operation.
866 if(contents && *contents){
867 for(p = contents; *p != '\0';){
868 line = p;
870 while(*p && *p != '\n')
871 p++;
873 save_p = NULL;
874 if(*p == '\n'){
875 save_p = p;
876 *p++ = '\0';
879 /* look for separator line */
880 if(strncmp(CACERTSTORELEADER, line, strlen(CACERTSTORELEADER)) == 0){
881 /* certtext is the content that should go in a file */
882 certtext = strstr(p, "-----BEGIN");
883 if(certtext != NULL){
884 if((q = strstr(certtext, CACERTSTORELEADER)) != NULL){
885 p = q;
887 else{ /* end of file */
888 q = certtext + strlen(certtext);
889 p = q;
892 in = BIO_new_mem_buf(certtext, q-certtext);
893 if(in){
894 tempfile = temp_nam(NULL, "az");
895 out = NULL;
896 if(tempfile)
897 out = BIO_new_file(tempfile, "w");
899 if(out){
900 while((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0)
901 BIO_write(out, iobuf, len);
903 BIO_free(out);
904 if(!X509_LOOKUP_load_file(lookup, tempfile, X509_FILETYPE_PEM))
905 failed++;
907 fs_give((void **) &tempfile);
910 BIO_free(in);
913 else{
914 p = p + strlen(p);
915 q_status_message1(SM_ORDER | SM_DING, 3, 3, _("Error in cacert container, missing BEGIN, certtext=%s"), certtext);
918 else{
919 p = p + strlen(p);
920 q_status_message1(SM_ORDER | SM_DING, 3, 3, _("Error in cacert container, missing separator, line=%s"), line);
923 if(save_p)
924 *save_p = '\n';
928 return(!failed);
933 certlist_to_file(char *filename, CertList *certlist)
935 CertList *cl;
936 BIO *bio_out = NULL;
937 int ret = -1;
939 if(filename && (bio_out=BIO_new_file(filename, "w")) != NULL){
940 ret = 0;
941 for(cl = certlist; cl; cl = cl->next){
942 if(cl->name && cl->name[0] && cl->x509_cert){
943 if(!((BIO_puts(bio_out, EMAILADDRLEADER) > 0)
944 && (BIO_puts(bio_out, cl->name) > 0)
945 && (BIO_puts(bio_out, "\n") > 0)))
946 ret = -1;
948 if(!PEM_write_bio_X509(bio_out, (X509 *) cl->x509_cert))
949 ret = -1;
953 BIO_free(bio_out);
956 return ret;
960 void
961 add_to_end_of_certlist(CertList **cl, char *name, X509 *cert)
963 CertList *new, *clp;
965 if(!cl)
966 return;
968 new = (CertList *) fs_get(sizeof(*new));
969 memset((void *) new, 0, sizeof(*new));
970 new->x509_cert = cert;
971 new->name = name ? cpystr(name) : NULL;
973 if(!*cl){
974 *cl = new;
976 else{
977 for(clp = (*cl); clp->next; clp = clp->next)
980 clp->next = new;
985 void
986 free_certlist(CertList **cl)
988 if(cl && *cl){
989 free_certlist(&(*cl)->next);
990 if((*cl)->name)
991 fs_give((void **) &(*cl)->name);
993 if((*cl)->x509_cert)
994 X509_free((X509 *) (*cl)->x509_cert);
996 fs_give((void **) cl);
1001 void
1002 free_personal_certs(PERSONAL_CERT **pc)
1004 if(pc && *pc){
1005 free_personal_certs(&(*pc)->next);
1006 if((*pc)->name)
1007 fs_give((void **) &(*pc)->name);
1009 if((*pc)->name)
1010 fs_give((void **) &(*pc)->name);
1012 if((*pc)->cert)
1013 X509_free((*pc)->cert);
1015 if((*pc)->key)
1016 EVP_PKEY_free((*pc)->key);
1018 fs_give((void **) pc);
1022 #endif /* SMIME */