1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: smkeys.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $";
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"
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"
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 certlist_to_file(char *filename
, CertList
*certlist
);
48 static int mem_add_extra_cacerts(char *contents
, X509_LOOKUP
*lookup
);
50 /* smime_expunge_cert.
51 * Return values: < 0 there was an error.
52 * >=0 the number of messages expunged
55 smime_expunge_cert(WhichCerts ctype
)
58 CertList
*cl
, *dummy
, *data
;
59 char *path
, *ext
, buf
[MAXPATH
+1];
61 if(DATACERT(ctype
)== NULL
)
64 /* data cert is the way we unify certificate management across functions, but it is
65 * not where we really save the information in the case ctype is equal to Private.
66 * What we will do is to update the datacert, and in the case of ctype equal to Private
67 * use the updated certdata to update the personal_certs data.
70 path
= PATHCERTDIR(ctype
);
74 /* add a fake certificate at the beginning of the list */
75 dummy
= fs_get(sizeof(CertList
));
76 memset((void *)dummy
, 0, sizeof(CertList
));
77 dummy
->next
= DATACERT(ctype
);
79 for(cl
= dummy
, count
= 0; cl
&& cl
->next
;){
80 if(cl
->next
->data
.deleted
== 0){
85 build_path(buf
, path
, cl
->next
->name
, sizeof(buf
));
86 if(ctype
== Private
&& strlen(buf
) + strlen(EXTCERT(Private
)) < sizeof(buf
))
87 strcat(buf
, EXTCERT(Private
));
89 if(our_unlink(buf
) < 0)
90 q_status_message1(SM_ORDER
, 3, 3, _("Error removing certificate %s"), cl
->next
->name
);
92 count
++; /* count it! */
94 cl
->next
= data
->next
;
95 if(data
->name
) fs_give((void **)&data
->name
);
96 fs_give((void **)&data
);
100 q_status_message1(SM_ORDER
, 3, 3, _("Error removing certificate %s"), cl
->name
);
103 case Private
: ps_global
->smime
->privatecertdata
= dummy
->next
; break;
104 case Public
: ps_global
->smime
->publiccertdata
= dummy
->next
; break;
105 case CACert
: ps_global
->smime
->cacertdata
= dummy
->next
; break;
108 fs_give((void **)&dummy
);
110 q_status_message2(SM_ORDER
, 3, 3, _("Removed %s certificate%s"), comatose(count
), plural(count
));
112 q_status_message(SM_ORDER
, 3, 3, _("Error: No certificates were removed"));
117 mark_cert_deleted(WhichCerts ctype
, char *email
, unsigned state
)
122 snprintf(tmp
, sizeof(tmp
), "%s%s", email
, ctype
== Private
? "" : ".crt");
123 tmp
[sizeof(tmp
)-1] = '\0';
124 for(cl
= DATACERT(ctype
); cl
!= NULL
&& strcmp(cl
->name
, tmp
); cl
= cl
->next
);
125 cl
->data
.deleted
= state
;
129 get_cert_deleted(WhichCerts ctype
, char *email
)
133 for(cl
= DATACERT(ctype
); cl
!= NULL
&& strcmp(cl
->name
, email
); cl
= cl
->next
);
134 return (cl
&& cl
->data
.deleted
) ? 1 : 0;
138 get_fingerprint(X509
*cert
, const EVP_MD
*type
, char *buf
, size_t maxLen
)
140 unsigned char md
[128];
146 X509_digest(cert
, type
, md
, &len
);
150 for(i
=0; i
<len
; i
++){
157 snprintf(b
, maxLen
- (b
-buf
), "%02x", md
[i
]);
164 * Remove leading whitespace, trailing whitespace and convert
165 * to lowercase. Also remove slash characters
167 * Args: s, -- The string to clean
169 * Result: the cleaned string
172 emailstrclean(char *string
)
174 char *s
= string
, *sc
= NULL
, *p
= NULL
;
176 for(; *s
; s
++){ /* single pass */
177 if(!isspace((unsigned char) (*s
))){
178 p
= NULL
; /* not start of blanks */
179 if(!sc
) /* first non-blank? */
180 sc
= string
; /* start copying */
182 else if(!p
) /* it's OK if sc == NULL */
183 p
= sc
; /* start of blanks? */
185 if(sc
&& *s
!='/' && *s
!='\\') /* if copying, copy */
186 *sc
++ = isupper((unsigned char) (*s
))
187 ? (unsigned char) tolower((unsigned char) (*s
))
188 : (unsigned char) (*s
);
191 if(p
) /* if ending blanks */
192 *p
= '\0'; /* tie off beginning */
193 else if(!sc
) /* never saw a non-blank */
194 *string
= '\0'; /* so tie whole thing off */
201 * Add a lookup for each "*.crt" file in the given directory.
204 add_certs_in_dir(X509_LOOKUP
*lookup
, char *path
, char *ext
, CertList
**cdata
)
212 if((dirp
= opendir(path
)) != NULL
){
213 while(!ret
&& (d
=readdir(dirp
)) != NULL
){
214 if(srchrstr(d
->d_name
, ext
)){
215 build_path(buf
, path
, d
->d_name
, sizeof(buf
));
217 if(!X509_LOOKUP_load_file(lookup
, buf
, X509_FILETYPE_PEM
)){
218 q_status_message1(SM_ORDER
, 3, 3, _("Error loading file %s"), buf
);
222 cert
= fs_get(sizeof(CertList
));
223 memset((void *)cert
, 0, sizeof(CertList
));
224 cert
->name
= cpystr(d
->d_name
);
228 for (cl
= *cdata
; cl
&& cl
->next
; cl
= cl
->next
);
246 * Get an X509_STORE. This consists of the system
247 * certs directory and any certificates in the user's
248 * ~/.alpine-smime/ca directory.
254 X509_STORE
*store
= NULL
;
256 dprint((9, "get_ca_store()"));
258 if(!(store
=X509_STORE_new())){
259 dprint((9, "X509_STORE_new() failed"));
263 if(!(lookup
=X509_STORE_add_lookup(store
, X509_LOOKUP_file()))){
264 dprint((9, "X509_STORE_add_lookup() failed"));
265 X509_STORE_free(store
);
269 if(ps_global
->smime
&& ps_global
->smime
->catype
== Container
270 && ps_global
->smime
->cacontent
){
272 if(!mem_add_extra_cacerts(ps_global
->smime
->cacontent
, lookup
)){
273 X509_STORE_free(store
);
277 else if(ps_global
->smime
&& ps_global
->smime
->catype
== Directory
278 && ps_global
->smime
->capath
){
279 if(add_certs_in_dir(lookup
, ps_global
->smime
->capath
, ".crt", &ps_global
->smime
->cacertdata
) < 0){
280 X509_STORE_free(store
);
285 if(!(lookup
=X509_STORE_add_lookup(store
, X509_LOOKUP_hash_dir()))){
286 X509_STORE_free(store
);
290 #ifdef SMIME_SSLCERTS
291 dprint((9, "get_ca_store(): adding cacerts from %s", SMIME_SSLCERTS
));
292 X509_LOOKUP_add_dir(lookup
, SMIME_SSLCERTS
, X509_FILETYPE_PEM
);
300 load_key(PERSONAL_CERT
*pc
, char *pass
)
303 EVP_PKEY
*key
= NULL
;
304 char buf
[MAXPATH
], file
[MAXPATH
];
306 if(!(ps_global
->smime
&& pc
&& pc
->name
))
309 if(ps_global
->smime
->privatetype
== Container
){
312 if(pc
->keytext
&& (q
= strstr(pc
->keytext
, "-----END")) != NULL
){
313 while(*q
&& *q
!= '\n')
319 if((in
= BIO_new_mem_buf(pc
->keytext
, q
-pc
->keytext
)) != NULL
){
320 key
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, pass
);
325 else if(ps_global
->smime
->privatetype
== Directory
){
326 /* filename is path/name.key */
327 strncpy(buf
, pc
->name
, sizeof(buf
)-5);
328 buf
[sizeof(buf
)-5] = '\0';
329 strncat(buf
, ".key", 5);
330 build_path(file
, ps_global
->smime
->privatepath
, buf
, sizeof(file
));
332 if(!(in
= BIO_new_file(file
, "r")))
335 key
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, pass
);
345 get_x509_name_entry(const char *key
, X509_NAME
*name
)
354 c
= X509_NAME_entry_count(name
);
359 e
= X509_NAME_get_entry(name
, i
);
366 n
= OBJ_obj2nid(e
->object
);
367 if((n
== NID_undef
) || ((id
=(char*) OBJ_nid2sn(n
)) == NULL
)){
368 i2t_ASN1_OBJECT(buf
, sizeof(buf
), e
->object
);
372 if((strucmp(id
, "email")==0) || (strucmp(id
, "emailAddress")==0)){
373 X509_NAME_get_text_by_OBJ(name
, e
->object
, buf
, sizeof(buf
)-1);
383 get_x509_subject_email(X509
*x
)
386 result
= get_x509_name_entry("email", X509_get_subject_name(x
));
388 result
= get_x509_name_entry("emailAddress", X509_get_subject_name(x
));
395 #include <openssl/x509v3.h>
397 * This newer version is from Adrian Vogel. It looks for the email
398 * address not only in the email address field, but also in an
399 * X509v3 extension field, Subject Altenative Name.
402 get_x509_subject_email(X509
*x
)
404 char **result
= NULL
;
406 STACK_OF(OPENSSL_STRING
) *emails
= X509_get1_email(x
);
407 if ((n
= sk_OPENSSL_STRING_num(emails
)) > 0) {
408 result
= fs_get((n
+1)*sizeof(char *));
409 for(i
= 0; i
< n
; i
++)
410 result
[i
] = cpystr(sk_OPENSSL_STRING_value(emails
, i
));
413 X509_email_free(emails
);
419 * Save the certificate for the given email address in
420 * ~/.alpine-smime/public.
422 * Should consider the security hazards in making a file with
423 * the email address that has come from the certificate.
425 * The argument email is destroyed.
427 * args: ctype says where the user wants to save the certificate
430 save_cert_for(char *email
, X509
*cert
, WhichCerts ctype
)
432 if(!ps_global
->smime
|| ctype
== Private
)
435 dprint((9, "save_cert_for(%s, %s)", email
? email
: "?", ctype
== Public
? _("Public") : ctype
== Private
? _("Private") : "CACert"));
436 emailstrclean(email
);
438 if(ps_global
->smime
->publictype
== Keychain
){
442 SecCertificateRef secCertificateRef
;
445 memset((void *) &certData
, 0, sizeof(certData
));
446 memset((void *) &secCertificateRef
, 0, sizeof(secCertificateRef
));
448 /* convert OpenSSL X509 cert data to MacOS certData */
449 if((certData
.Length
= i2d_X509(cert
, &(certData
.Data
))) > 0){
452 * Put that certData into a SecCertificateRef.
453 * Version 3 should work for versions 1-3.
455 if(!(rc
=SecCertificateCreateFromData(&certData
,
457 CSSM_CERT_ENCODING_DER
,
458 &secCertificateRef
))){
460 /* add it to the default keychain */
461 if(!(rc
=SecCertificateAddToKeychain(secCertificateRef
, NULL
))){
464 else if(rc
== errSecDuplicateItem
){
465 dprint((9, "save_cert_for: certificate for %s already in keychain", email
));
468 dprint((9, "SecCertificateAddToKeychain failed"));
472 dprint((9, "SecCertificateCreateFromData failed"));
476 dprint((9, "i2d_X509 failed"));
479 #endif /* APPLEKEYCHAIN */
481 else if(ps_global
->smime
->publictype
== Container
){
482 REMDATA_S
*rd
= NULL
;
484 char *upath
= PATHCERTDIR(ctype
);
485 char *tempfile
= NULL
;
488 add_to_end_of_certlist(&ps_global
->smime
->publiccertlist
, email
, X509_dup(cert
));
493 if(IS_REMOTE(upath
)){
494 rd
= rd_create_remote(RemImap
, upath
, REMOTE_SMIME_SUBTYPE
,
496 _("Can't access remote smime configuration."));
501 (void) rd_read_metadata(rd
);
503 if(rd
->access
== MaybeRorW
){
504 if(rd
->read_status
== 'R')
505 rd
->access
= ReadOnly
;
507 rd
->access
= ReadWrite
;
510 if(rd
->access
!= NoExists
){
512 rd_check_remvalid(rd
, 1L);
515 * If the cached info says it is readonly but
516 * it looks like it's been fixed now, change it to readwrite.
518 if(rd
->read_status
== 'R'){
519 rd_check_readonly_access(rd
);
520 if(rd
->read_status
== 'W'){
521 rd
->access
= ReadWrite
;
522 rd
->flags
|= REM_OUTOFDATE
;
525 rd
->access
= ReadOnly
;
529 if(rd
->flags
& REM_OUTOFDATE
){
530 if(rd_update_local(rd
) != 0){
532 dprint((1, "save_cert_for: rd_update_local failed\n"));
533 rd_close_remdata(&rd
);
540 if(rd
->access
!= ReadWrite
|| rd_remote_is_readonly(rd
)){
541 rd_close_remdata(&rd
);
545 rd
->flags
|= DO_REMTRIM
;
547 strncpy(path
, rd
->lf
, sizeof(path
)-1);
548 path
[sizeof(path
)-1] = '\0';
551 strncpy(path
, upath
, sizeof(path
)-1);
552 path
[sizeof(path
)-1] = '\0';
555 tempfile
= tempfile_in_same_dir(path
, "az", NULL
);
557 if(certlist_to_file(tempfile
, ps_global
->smime
->publiccertlist
))
561 if(rename_file(tempfile
, path
) < 0){
562 q_status_message2(SM_ORDER
, 3, 3,
563 _("Can't rename %s to %s"), tempfile
, path
);
568 if(!err
&& IS_REMOTE(upath
)){
574 we_cancel
= busy_cue(_("Copying to remote smime container"), NULL
, 1);
575 if((e
= rd_update_remote(rd
, datebuf
)) != 0){
577 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
578 _("Error opening temporary smime file %s: %s"),
579 rd
->lf
, error_description(errno
));
581 "write_remote_smime: error opening temp file %s\n",
582 rd
->lf
? rd
->lf
: "?"));
585 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
586 _("Error copying to %s: %s"),
587 rd
->rn
, error_description(errno
));
589 "write_remote_smime: error copying from %s to %s\n",
590 rd
->lf
? rd
->lf
: "?", rd
->rn
? rd
->rn
: "?"));
593 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
594 _("Copy of smime cert to remote folder failed, changes NOT saved remotely"));
597 rd_update_metadata(rd
, datebuf
);
598 rd
->read_status
= 'W';
601 rd_close_remdata(&rd
);
607 fs_give((void **) &tempfile
);
610 else if(ps_global
->smime
->publictype
== Directory
){
611 char *path
= PATHCERTDIR(ctype
);
612 char certfilename
[MAXPATH
];
615 build_path(certfilename
, path
, email
, sizeof(certfilename
));
616 strncat(certfilename
, ".crt", sizeof(certfilename
)-1-strlen(certfilename
));
617 certfilename
[sizeof(certfilename
)-1] = 0;
619 bio_out
= BIO_new_file(certfilename
, "w");
621 PEM_write_bio_X509(bio_out
, cert
);
623 q_status_message1(SM_ORDER
, 1, 1, _("Saved certificate for <%s>"), email
);
626 q_status_message1(SM_ORDER
, 1, 1, _("Couldn't save certificate for <%s>"), email
);
633 * Try to retrieve the certificate for the given email address.
634 * The caller should free the cert.
637 get_cert_for(char *email
, WhichCerts ctype
)
640 char certfilename
[MAXPATH
];
641 char emailaddr
[MAXPATH
];
645 if(!ps_global
->smime
)
648 dprint((9, "get_cert_for(%s, %s)", email
? email
: "?", "none yet"));
650 if(ctype
== Private
) /* there is no private certificate info */
651 ctype
= Public
; /* return public information instead */
652 strncpy(emailaddr
, email
, sizeof(emailaddr
)-1);
653 emailaddr
[sizeof(emailaddr
)-1] = 0;
655 /* clean it up (lowercase, space removal) */
656 emailstrclean(emailaddr
);
658 if(ps_global
->smime
->publictype
== Keychain
){
662 SecKeychainItemRef itemRef
= nil
;
663 SecKeychainAttributeList attrList
;
664 SecKeychainAttribute attrib
;
665 SecKeychainSearchRef searchRef
= nil
;
668 /* low-level form of MacOS data */
669 memset((void *) &certData
, 0, sizeof(certData
));
672 attrList
.attr
= &attrib
;
674 /* kSecAlias means email address for a certificate */
675 attrib
.tag
= kSecAlias
;
676 attrib
.data
= emailaddr
;
677 attrib
.length
= strlen(attrib
.data
);
679 /* Find the certificate in the default keychain */
680 if(!(rc
=SecKeychainSearchCreateFromAttributes(NULL
,
681 kSecCertificateItemClass
,
685 if(!(rc
=SecKeychainSearchCopyNext(searchRef
, &itemRef
))){
687 /* extract the data portion of the certificate */
688 if(!(rc
=SecCertificateGetData((SecCertificateRef
) itemRef
, &certData
))){
691 * Convert it from MacOS form to OpenSSL form.
692 * The input is certData from above and the output
695 if(!d2i_X509(&cert
, &(certData
.Data
), certData
.Length
)){
696 dprint((9, "d2i_X509 failed"));
700 dprint((9, "SecCertificateGetData failed"));
703 else if(rc
== errSecItemNotFound
){
704 dprint((9, "get_cert_for: Public cert for %s not found", emailaddr
));
707 dprint((9, "SecKeychainSearchCopyNext failed"));
711 dprint((9, "SecKeychainSearchCreateFromAttributes failed"));
715 CFRelease(searchRef
);
717 #endif /* APPLEKEYCHAIN */
719 else if(SMHOLDERTYPE(ctype
) == Container
){
722 for(cl
= SMCERTLIST(ctype
); cl
; cl
= cl
->next
){
723 if(cl
->name
&& !strucmp(emailaddr
, cl
->name
))
728 cert
= X509_dup((X509
*) cl
->x509_cert
);
730 else if(SMHOLDERTYPE(ctype
) == Directory
){
731 build_path(certfilename
, PATHCERTDIR(ctype
), emailaddr
, sizeof(certfilename
));
732 strncat(certfilename
, EXTCERT(ctype
), sizeof(certfilename
)-1-strlen(certfilename
));
733 certfilename
[sizeof(certfilename
)-1] = 0;
735 if((in
= BIO_new_file(certfilename
, "r"))!=0){
737 cert
= PEM_read_bio_X509(in
, NULL
, NULL
, NULL
);
740 /* could check email addr in cert matches */
752 mem_to_personal_certs(char *contents
)
754 PERSONAL_CERT
*result
= NULL
;
755 char *p
, *q
, *line
, *name
, *keytext
, *save_p
;
758 if(contents
&& *contents
){
759 for(p
= contents
; *p
!= '\0';){
762 while(*p
&& *p
!= '\n')
771 if(strncmp(EMAILADDRLEADER
, line
, strlen(EMAILADDRLEADER
)) == 0){
772 name
= line
+ strlen(EMAILADDRLEADER
);
773 cert
= get_cert_for(name
, Public
);
776 /* advance p past this record */
777 if((q
= strstr(keytext
, "-----END")) != NULL
){
778 while(*q
&& *q
!= '\n')
788 q_status_message(SM_ORDER
| SM_DING
, 3, 3, _("Error in privatekey container, missing END"));
794 pc
= (PERSONAL_CERT
*) fs_get(sizeof(*pc
));
796 pc
->name
= cpystr(name
);
797 pc
->keytext
= keytext
; /* a pointer into contents */
799 pc
->key
= load_key(pc
, "");
816 mem_to_certlist(char *contents
)
818 CertList
*ret
= NULL
;
819 char *p
, *q
, *line
, *name
, *certtext
, *save_p
;
823 if(contents
&& *contents
){
824 for(p
= contents
; *p
!= '\0';){
827 while(*p
&& *p
!= '\n')
836 if(strncmp(EMAILADDRLEADER
, line
, strlen(EMAILADDRLEADER
)) == 0){
837 name
= line
+ strlen(EMAILADDRLEADER
);
840 if(strncmp("-----BEGIN", certtext
, strlen("-----BEGIN")) == 0){
841 if((q
= strstr(certtext
, "-----END")) != NULL
){
842 while(*q
&& *q
!= '\n')
850 if((in
= BIO_new_mem_buf(certtext
, q
-certtext
)) != 0){
851 cert
= PEM_read_bio_X509(in
, NULL
, NULL
, NULL
);
859 q_status_message1(SM_ORDER
| SM_DING
, 3, 3, _("Error in publiccert container, missing BEGIN, certtext=%s"), certtext
);
863 add_to_end_of_certlist(&ret
, name
, cert
);
877 * Add the CACert Container contents into the CACert store.
879 * Returns > 0 for success, 0 for failure
882 mem_add_extra_cacerts(char *contents
, X509_LOOKUP
*lookup
)
884 char *p
, *q
, *line
, *certtext
, *save_p
;
891 * The most straight-forward way to do this is to write
892 * the container contents to a temp file and then load the
893 * contents of the file with X509_LOOKUP_load_file(), like
894 * is done in add_certs_in_dir(). What we don't know is if
895 * each file should consist of one cacert or if they can all
896 * just be jammed together into one file. To be safe, we'll use
897 * one file per and do each in a separate operation.
900 if(contents
&& *contents
){
901 for(p
= contents
; *p
!= '\0';){
904 while(*p
&& *p
!= '\n')
913 /* look for separator line */
914 if(strncmp(CACERTSTORELEADER
, line
, strlen(CACERTSTORELEADER
)) == 0){
915 /* certtext is the content that should go in a file */
917 if(strncmp("-----BEGIN", certtext
, strlen("-----BEGIN")) == 0){
918 if((q
= strstr(certtext
, CACERTSTORELEADER
)) != NULL
){
921 else{ /* end of file */
922 q
= certtext
+ strlen(certtext
);
926 in
= BIO_new_mem_buf(certtext
, q
-certtext
);
928 tempfile
= temp_nam(NULL
, "az");
931 out
= BIO_new_file(tempfile
, "w");
934 while((len
= BIO_read(in
, iobuf
, sizeof(iobuf
))) > 0)
935 BIO_write(out
, iobuf
, len
);
938 if(!X509_LOOKUP_load_file(lookup
, tempfile
, X509_FILETYPE_PEM
))
941 fs_give((void **) &tempfile
);
949 q_status_message1(SM_ORDER
| SM_DING
, 3, 3, _("Error in cacert container, missing BEGIN, certtext=%s"), certtext
);
954 q_status_message1(SM_ORDER
| SM_DING
, 3, 3, _("Error in cacert container, missing separator, line=%s"), line
);
967 certlist_to_file(char *filename
, CertList
*certlist
)
973 if(filename
&& (bio_out
=BIO_new_file(filename
, "w")) != NULL
){
975 for(cl
= certlist
; cl
; cl
= cl
->next
){
976 if(cl
->name
&& cl
->name
[0] && cl
->x509_cert
){
977 if(!((BIO_puts(bio_out
, EMAILADDRLEADER
) > 0)
978 && (BIO_puts(bio_out
, cl
->name
) > 0)
979 && (BIO_puts(bio_out
, "\n") > 0)))
982 if(!PEM_write_bio_X509(bio_out
, (X509
*) cl
->x509_cert
))
995 add_to_end_of_certlist(CertList
**cl
, char *name
, X509
*cert
)
1002 new = (CertList
*) fs_get(sizeof(*new));
1003 memset((void *) new, 0, sizeof(*new));
1004 new->x509_cert
= cert
;
1005 new->name
= name
? cpystr(name
) : NULL
;
1011 for(clp
= (*cl
); clp
->next
; clp
= clp
->next
)
1020 free_certlist(CertList
**cl
)
1023 free_certlist(&(*cl
)->next
);
1025 fs_give((void **) &(*cl
)->name
);
1027 if((*cl
)->x509_cert
)
1028 X509_free((X509
*) (*cl
)->x509_cert
);
1030 fs_give((void **) cl
);
1036 free_personal_certs(PERSONAL_CERT
**pc
)
1039 free_personal_certs(&(*pc
)->next
);
1041 fs_give((void **) &(*pc
)->name
);
1044 fs_give((void **) &(*pc
)->name
);
1047 X509_free((*pc
)->cert
);
1050 EVP_PKEY_free((*pc
)->key
);
1052 fs_give((void **) pc
);