From 2bca915f0a00ac4295bc40e98fbc613393dc3542 Mon Sep 17 00:00:00 2001 From: "Steffen (Daode) Nurpmeso" Date: Fri, 14 Feb 2014 13:12:31 +0100 Subject: [PATCH] NYD: ssl.c --- catd/en_US | 2 +- extern.h | 32 ++- nail.h | 12 +- openssl.c | 12 +- ssl.c | 860 ++++++++++++++++++++++++++++++++----------------------------- 5 files changed, 489 insertions(+), 429 deletions(-) rewrite ssl.c (75%) diff --git a/catd/en_US b/catd/en_US index 80827b03..774428b0 100644 --- a/catd/en_US +++ b/catd/en_US @@ -272,7 +272,7 @@ $set 1 262 SSL_new() failed 263 could not initiate SSL/TLS connection 264 $Continue (y/n)? $ -265 invalid value of ssl-verify: %s\n +265 Invalid value of %s: %s\n 266 Ignoring header field "%s"\n 267 Restoring deleted header lines\n 268 Pipe to: "%s"\n diff --git a/extern.h b/extern.h index f347a263..85986a4c 100644 --- a/extern.h +++ b/extern.h @@ -1389,20 +1389,40 @@ FL int cspam_spam(void *v); # define cspam_spam ccmdnotsupp #endif -/* ssl.c */ +/* + * ssl.c + */ + #ifdef HAVE_SSL -FL void ssl_set_vrfy_level(const char *uhp); -FL enum okay ssl_vrfy_decide(void); -FL char * ssl_method_string(const char *uhp); +/* */ +FL void ssl_set_verify_level(char const *uhp); + +/* */ +FL enum okay ssl_verify_decide(void); + +/* */ +FL char * ssl_method_string(char const *uhp); + +/* */ FL enum okay smime_split(FILE *ip, FILE **hp, FILE **bp, long xcount, int keep); + +/* */ FL FILE * smime_sign_assemble(FILE *hp, FILE *bp, FILE *sp); + +/* */ FL FILE * smime_encrypt_assemble(FILE *hp, FILE *yp); + +/* */ FL struct message * smime_decrypt_assemble(struct message *m, FILE *hp, FILE *bp); + +/* */ FL int ccertsave(void *v); -FL enum okay rfc2595_hostname_match(const char *host, const char *pattern); -#else + +/* */ +FL enum okay rfc2595_hostname_match(char const *host, char const *pattern); +#else /* HAVE_SSL */ # define ccertsave ccmdnotsupp #endif diff --git a/nail.h b/nail.h index 0a3b78f2..5f131057 100644 --- a/nail.h +++ b/nail.h @@ -623,11 +623,11 @@ enum protocol { }; #ifdef HAVE_SSL -enum ssl_vrfy_level { - VRFY_IGNORE, - VRFY_WARN, - VRFY_ASK, - VRFY_STRICT +enum ssl_verify_level { + SSL_VERIFY_IGNORE, + SSL_VERIFY_WARN, + SSL_VERIFY_ASK, + SSL_VERIFY_STRICT }; #endif @@ -1456,7 +1456,7 @@ VL struct colour_table *colour_table; #endif #ifdef HAVE_SSL -VL enum ssl_vrfy_level ssl_vrfy_level; /* SSL verification level */ +VL enum ssl_verify_level ssl_verify_level; /* SSL verification level */ #endif #ifdef HAVE_ICONV diff --git a/openssl.c b/openssl.c index 3bfbbba1..d9f655ae 100644 --- a/openssl.c +++ b/openssl.c @@ -233,7 +233,7 @@ ssl_verify_cb(int success, X509_STORE_CTX *store) fprintf(stderr, tr(231, " subject = %s\n"), data); fprintf(stderr, tr(232, " err %i: %s\n"), err, X509_verify_cert_error_string(err)); - if (ssl_vrfy_decide() != OKAY) + if (ssl_verify_decide() != OKAY) rv = FAL0; } NYD_LEAVE; @@ -270,7 +270,7 @@ ssl_load_verifications(struct sock *sp) X509_STORE *store; NYD_ENTER; - if (ssl_vrfy_level == VRFY_IGNORE) + if (ssl_verify_level == SSL_VERIFY_IGNORE) goto jleave; if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL) @@ -809,7 +809,7 @@ ssl_open(char const *server, struct sock *sp, char const *uhp) NYD_ENTER; ssl_init(); - ssl_set_vrfy_level(uhp); + ssl_set_verify_level(uhp); if ((sp->s_ctx = SSL_CTX_new(UNCONST(ssl_select_method(uhp)))) == NULL) { ssl_gen_err(tr(261, "SSL_CTX_new() failed")); goto jleave; @@ -839,11 +839,11 @@ ssl_open(char const *server, struct sock *sp, char const *uhp) ssl_gen_err(tr(263, "could not initiate SSL/TLS connection")); goto jleave; } - if (ssl_vrfy_level != VRFY_IGNORE) { + if (ssl_verify_level != SSL_VERIFY_IGNORE) { if (ssl_check_host(server, sp) != OKAY) { fprintf(stderr, tr(249, "host certificate does not match \"%s\"\n"), server); - if (ssl_vrfy_decide() != OKAY) + if (ssl_verify_decide() != OKAY) goto jleave; } } @@ -879,7 +879,7 @@ cverify(void *vp) ssl_init(); - ssl_vrfy_level = VRFY_STRICT; + ssl_verify_level = SSL_VERIFY_STRICT; if ((store = X509_STORE_new()) == NULL) { ssl_gen_err(tr(544, "Error creating X509 store")); goto jleave; diff --git a/ssl.c b/ssl.c dissimilarity index 75% index a87888e1..e49073e0 100644 --- a/ssl.c +++ b/ssl.c @@ -1,410 +1,450 @@ -/*@ S-nail - a mail user agent derived from Berkeley Mail. - *@ Generic SSL / SMIME commands. - * - * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany. - * Copyright (c) 2012 - 2014 Steffen "Daode" Nurpmeso . - */ -/* - * Copyright (c) 2002 - * Gunnar Ritter. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Gunnar Ritter - * and his contributors. - * 4. Neither the name of Gunnar Ritter nor the names of his contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef HAVE_AMALGAMATION -# include "nail.h" -#endif - -EMPTY_FILE(ssl) -#ifdef HAVE_SSL -FL void -ssl_set_vrfy_level(const char *uhp) -{ - size_t l; - char *cp, *vrvar; - - ssl_vrfy_level = VRFY_ASK; - l = strlen(uhp); - vrvar = ac_alloc(l + 12); - memcpy(vrvar, "ssl-verify-", 11); - memcpy(vrvar + 11, uhp, l + 1); - - if ((cp = vok_vlook(vrvar)) == NULL) - cp = ok_vlook(ssl_verify); - ac_free(vrvar); - if (cp != NULL) { - if (strcmp(cp, "strict") == 0) - ssl_vrfy_level = VRFY_STRICT; - else if (strcmp(cp, "ask") == 0) - ssl_vrfy_level = VRFY_ASK; - else if (strcmp(cp, "warn") == 0) - ssl_vrfy_level = VRFY_WARN; - else if (strcmp(cp, "ignore") == 0) - ssl_vrfy_level = VRFY_IGNORE; - else - fprintf(stderr, tr(265, - "invalid value of ssl-verify: %s\n"), cp); - } -} - -FL enum okay -ssl_vrfy_decide(void) -{ - enum okay ok = STOP; - - switch (ssl_vrfy_level) { - case VRFY_STRICT: - ok = STOP; - break; - case VRFY_ASK: - { - char *line = NULL; - size_t linesize = 0; - - fprintf(stderr, tr(264, "Continue (y/n)? ")); - if (readline_restart(stdin, &line, &linesize, 0) > 0 && - *line == 'y') - ok = OKAY; - else - ok = STOP; - if (line) - free(line); - } - break; - case VRFY_WARN: - case VRFY_IGNORE: - ok = OKAY; - } - return ok; -} - -FL char * -ssl_method_string(const char *uhp) -{ - size_t l; - char *cp, *mtvar; - - l = strlen(uhp); - mtvar = ac_alloc(l + 12); - memcpy(mtvar, "ssl-method-", 11); - memcpy(mtvar + 11, uhp, l + 1); - if ((cp = vok_vlook(mtvar)) == NULL) - cp = ok_vlook(ssl_method); - ac_free(mtvar); - return cp; -} - -FL enum okay -smime_split(FILE *ip, FILE **hp, FILE **bp, long xcount, int keep) -{ - /* TODO like i said quite often now, the entire SSL stuff really needs - * TODO a review ASAP; also in respect to correct resource release, and - * TODO especially in case of errors; S-nail is a program that REALLY - * TODO may run for a week or longer!!! */ - char *buf, *hn, *bn; - char *savedfields = NULL; - size_t bufsize, buflen, cnt, savedsize = 0; - int c; - - if ((*hp = Ftemp(&hn, "Rh", "w+", 0600, 1)) == NULL) - goto jetmp; - rm(hn); - Ftfree(&hn); - if ((*bp = Ftemp(&bn, "Rb", "w+", 0600, 1)) == NULL) { -jetmp: - perror("tempfile"); - return STOP; - } - rm(bn); - Ftfree(&bn); - - buf = smalloc(bufsize = LINESIZE); - savedfields = smalloc(savedsize = 1); - *savedfields = '\0'; - if (xcount < 0) - cnt = fsize(ip); - else - cnt = xcount; - - while (fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0) != NULL && - *buf != '\n') { - if (ascncasecmp(buf, "content-", 8) == 0) { - if (keep) - fputs("X-Encoded-", *hp); - for (;;) { - savedsize += buflen; - savedfields = srealloc(savedfields, savedsize); - strcat(savedfields, buf); - if (keep) - fwrite(buf, sizeof *buf, buflen, *hp); - c = getc(ip); - ungetc(c, ip); - if (!blankchar(c)) - break; - fgetline(&buf, &bufsize, &cnt, &buflen, - ip, 0); - } - continue; - } - fwrite(buf, sizeof *buf, buflen, *hp); - } - fflush(*hp); - rewind(*hp); - - fputs(savedfields, *bp); - putc('\n', *bp); - while (fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0) != NULL) - fwrite(buf, sizeof *buf, buflen, *bp); - fflush(*bp); - rewind(*bp); - - free(savedfields); - free(buf); - return OKAY; -} - -FL FILE * -smime_sign_assemble(FILE *hp, FILE *bp, FILE *sp) -{ - char *boundary, *cp; - FILE *op; - int c, lastc = EOF; - - if ((op = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) { - perror("tempfile"); - return NULL; - } - rm(cp); - Ftfree(&cp); - boundary = mime_create_boundary(); - while ((c = getc(hp)) != EOF) { - if (c == '\n' && lastc == '\n') - break; - putc(c, op); - lastc = c; - } - fprintf(op, "Content-Type: multipart/signed;\n" - " protocol=\"application/x-pkcs7-signature\"; micalg=sha1;\n" - " boundary=\"%s\"\n\n", boundary); - fprintf(op, "This is an S/MIME signed message.\n\n--%s\n", - boundary); - while ((c = getc(bp)) != EOF) - putc(c, op); - fprintf(op, "\n--%s\n", boundary); - fputs("Content-Type: application/x-pkcs7-signature; " - "name=\"smime.p7s\"\n" - "Content-Transfer-Encoding: base64\n" - "Content-Disposition: attachment; filename=\"smime.p7s\"\n\n", - op); - while ((c = getc(sp)) != EOF) { - if (c == '-') { - while ((c = getc(sp)) != EOF && c != '\n'); - continue; - } - putc(c, op); - } - fprintf(op, "\n--%s--\n", boundary); - Fclose(hp); - Fclose(bp); - Fclose(sp); - fflush(op); - if (ferror(op)) { - perror("signed output data"); - Fclose(op); - return NULL; - } - rewind(op); - return op; -} - -FL FILE * -smime_encrypt_assemble(FILE *hp, FILE *yp) -{ - char *cp; - FILE *op; - int c, lastc = EOF; - - if ((op = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) { - perror("tempfile"); - return NULL; - } - rm(cp); - Ftfree(&cp); - while ((c = getc(hp)) != EOF) { - if (c == '\n' && lastc == '\n') - break; - putc(c, op); - lastc = c; - } - fprintf(op, "Content-Type: application/x-pkcs7-mime; " - "name=\"smime.p7m\"\n" - "Content-Transfer-Encoding: base64\n" - "Content-Disposition: attachment; " - "filename=\"smime.p7m\"\n\n"); - while ((c = getc(yp)) != EOF) { - if (c == '-') { - while ((c = getc(yp)) != EOF && c != '\n'); - continue; - } - putc(c, op); - } - Fclose(hp); - Fclose(yp); - fflush(op); - if (ferror(op)) { - perror("encrypted output data"); - Fclose(op); - return NULL; - } - rewind(op); - return op; -} - -FL struct message * -smime_decrypt_assemble(struct message *m, FILE *hp, FILE *bp) -{ - ui32_t lastnl = 0; - int binary = 0; - char *buf = NULL; - size_t bufsize = 0, buflen, cnt; - long lines = 0, octets = 0; - struct message *x; - off_t offset; - - x = salloc(sizeof *x); - *x = *m; - fflush(mb.mb_otf); - fseek(mb.mb_otf, 0L, SEEK_END); - offset = ftell(mb.mb_otf); - cnt = fsize(hp); - while (fgetline(&buf, &bufsize, &cnt, &buflen, hp, 0) != NULL) { - char const *cp; - if (buf[0] == '\n') - break; - if ((cp = thisfield(buf, "content-transfer-encoding")) != NULL) - if (ascncasecmp(cp, "binary", 7) == 0) - binary = 1; - fwrite(buf, sizeof *buf, buflen, mb.mb_otf); - octets += buflen; - lines++; - } - octets += mkdate(mb.mb_otf, "X-Decoding-Date"); - lines++; - cnt = fsize(bp); - while (fgetline(&buf, &bufsize, &cnt, &buflen, bp, 0) != NULL) { - lines++; - if (!binary && buf[buflen-1] == '\n' && buf[buflen-2] == '\r') - buf[--buflen-1] = '\n'; - fwrite(buf, sizeof *buf, buflen, mb.mb_otf); - octets += buflen; - if (buf[0] == '\n') - lastnl++; - else if (buf[buflen-1] == '\n') - lastnl = 1; - else - lastnl = 0; - } - while (!binary && lastnl < 2) { - putc('\n', mb.mb_otf); - lines++; - octets++; - lastnl++; - } - Fclose(hp); - Fclose(bp); - free(buf); - fflush(mb.mb_otf); - if (ferror(mb.mb_otf)) { - perror("decrypted output data"); - return NULL; - } - x->m_size = x->m_xsize = octets; - x->m_lines = x->m_xlines = lines; - x->m_block = mailx_blockof(offset); - x->m_offset = mailx_offsetof(offset); - return x; -} - -FL int -ccertsave(void *v) -{ - int *ip; - int *msgvec; - char *file = NULL, *str = v; - int val = 0; - FILE *fp; - bool_t f; - - msgvec = salloc((msgCount + 2) * sizeof *msgvec); - if ((file = laststring(str, &f, 1)) == NULL) { - fprintf(stderr, "No file to save certificate given.\n"); - return 1; - } - if (!f) { - *msgvec = first(0, MMNORM); - if (*msgvec == 0) { - if (inhook) - return 0; - fprintf(stderr, - "No messages to get certificates from.\n"); - return 1; - } - msgvec[1] = 0; - } else if (getmsglist(str, msgvec, 0) < 0) - return 1; - if (*msgvec == 0) { - if (inhook) - return 0; - fprintf(stderr, "No applicable messages.\n"); - return 1; - } - if ((fp = Fopen(file, "a")) == NULL) { - perror(file); - return 1; - } - for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) - if (smime_certsave(&message[*ip-1], *ip, fp) != OKAY) - val = 1; - Fclose(fp); - if (val == 0) - printf("Certificate(s) saved.\n"); - return val; -} - -FL enum okay -rfc2595_hostname_match(const char *host, const char *pattern) -{ - if (pattern[0] == '*' && pattern[1] == '.') { - pattern++; - while (*host && *host != '.') - host++; - } - return asccasecmp(host, pattern) == 0 ? OKAY : STOP; -} -#endif /* HAVE_SSL */ +/*@ S-nail - a mail user agent derived from Berkeley Mail. + *@ Generic SSL / S/MIME commands. + * + * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany. + * Copyright (c) 2012 - 2014 Steffen "Daode" Nurpmeso . + */ +/* + * Copyright (c) 2002 + * Gunnar Ritter. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Gunnar Ritter + * and his contributors. + * 4. Neither the name of Gunnar Ritter nor the names of his contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HAVE_AMALGAMATION +# include "nail.h" +#endif + +EMPTY_FILE(ssl) +#ifdef HAVE_SSL +struct ssl_verify_levels { + char const sv_name[8]; + enum ssl_verify_level sv_level; +}; + +/* Supported SSL/TLS verification methods: update manual on change! */ +static struct ssl_verify_levels const _ssl_verify_levels[] = { + {"strict", SSL_VERIFY_STRICT}, + {"ask", SSL_VERIFY_ASK}, + {"warn", SSL_VERIFY_WARN}, + {"ignore", SSL_VERIFY_IGNORE} +}; + +FL void +ssl_set_verify_level(char const *uhp) +{ + size_t i; + char *cp, *vrvar; + NYD_ENTER; + + ssl_verify_level = SSL_VERIFY_ASK; + + i = strlen(uhp); + vrvar = ac_alloc(11u + i +1); + memcpy(vrvar, "ssl-verify-", 11u); + memcpy(vrvar + 11u, uhp, i +1); + + cp = vok_vlook(vrvar); + if (cp == NULL) { + vrvar[10] = '\0'; + cp = ok_vlook(ssl_verify); + } + + if (cp != NULL) { + for (i = 0; i < NELEM(_ssl_verify_levels); ++i) + if (!strcmp(_ssl_verify_levels[i].sv_name, cp)) { + ssl_verify_level = _ssl_verify_levels[i].sv_level; + goto jleave; + } + fprintf(stderr, tr(265, "Invalid value of %s: %s\n"), vrvar, cp); + } +jleave: + ac_free(vrvar); + NYD_LEAVE; +} + +FL enum okay +ssl_verify_decide(void) +{ + enum okay rv = STOP; + NYD_ENTER; + + switch (ssl_verify_level) { + case SSL_VERIFY_STRICT: + rv = STOP; + break; + case SSL_VERIFY_ASK: + rv = getapproval(NULL, FAL0) ? OKAY : STOP; + break; + case SSL_VERIFY_WARN: + case SSL_VERIFY_IGNORE: + rv = OKAY; + break; + } + NYD_LEAVE; + return rv; +} + +FL char * +ssl_method_string(char const *uhp) +{ + size_t l; + char *cp, *mtvar; + NYD_ENTER; + + l = strlen(uhp); + mtvar = ac_alloc(11u + l +1); + memcpy(mtvar, "ssl-method-", 11); + memcpy(mtvar + 11, uhp, l +1); + if ((cp = vok_vlook(mtvar)) == NULL) + cp = ok_vlook(ssl_method); + ac_free(mtvar); + NYD_LEAVE; + return cp; +} + +FL enum okay +smime_split(FILE *ip, FILE **hp, FILE **bp, long xcount, int keep) +{ + char *buf, *savedfields/* TODO use struct str or local per-line xy */ = NULL; + size_t bufsize, buflen, cnt, savedsize = 0; + int c; + enum okay rv = STOP; + NYD_ENTER; + + if ((*hp = Ftmp(NULL, "smimeh", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) == + NULL) + goto jetmp; + if ((*bp = Ftmp(NULL, "smimeb", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) == + NULL) { + Fclose(*hp); +jetmp: + perror("tempfile"); + goto jleave; + } + + buf = smalloc(bufsize = LINESIZE); + savedfields = smalloc(savedsize = 1); + *savedfields = '\0'; + if (xcount < 0) + cnt = fsize(ip); + else + cnt = xcount; + + while (fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0) != NULL && + *buf != '\n') { + if (!ascncasecmp(buf, "content-", 8)) { + if (keep) + fputs("X-Encoded-", *hp); + for (;;) { + savedsize += buflen; + savedfields = srealloc(savedfields, savedsize); + strcat(savedfields, buf); + if (keep) + fwrite(buf, sizeof *buf, buflen, *hp); + c = getc(ip); + ungetc(c, ip); + if (!blankchar(c)) + break; + fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0); + } + continue; + } + fwrite(buf, sizeof *buf, buflen, *hp); + } + fflush_rewind(*hp); + + fputs(savedfields, *bp); + putc('\n', *bp); + while (fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0) != NULL) + fwrite(buf, sizeof *buf, buflen, *bp); + fflush_rewind(*bp); + + free(savedfields); + free(buf); + rv = OKAY; +jleave: + NYD_LEAVE; + return rv; +} + +FL FILE * +smime_sign_assemble(FILE *hp, FILE *bp, FILE *sp) +{ + char *boundary; + int c, lastc = EOF; + FILE *op; + NYD_ENTER; + + if ((op = Ftmp(NULL, "smimea", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) == + NULL) { + perror("tempfile"); + goto jleave; + } + + while ((c = getc(hp)) != EOF) { + if (c == '\n' && lastc == '\n') + break; + putc(c, op); + lastc = c; + } + + boundary = mime_create_boundary(); + fprintf(op, "Content-Type: multipart/signed;\n" + " protocol=\"application/x-pkcs7-signature\"; micalg=sha1;\n" + " boundary=\"%s\"\n\n", boundary); + fprintf(op, "This is an S/MIME signed message.\n\n--%s\n", boundary); + while ((c = getc(bp)) != EOF) + putc(c, op); + + fprintf(op, "\n--%s\n", boundary); + fputs("Content-Type: application/x-pkcs7-signature; name=\"smime.p7s\"\n" + "Content-Transfer-Encoding: base64\n" + "Content-Disposition: attachment; filename=\"smime.p7s\"\n\n", op); + while ((c = getc(sp)) != EOF) { + if (c == '-') { + while ((c = getc(sp)) != EOF && c != '\n'); + continue; + } + putc(c, op); + } + + fprintf(op, "\n--%s--\n", boundary); + + Fclose(hp); + Fclose(bp); + Fclose(sp); + + fflush(op); + if (ferror(op)) { + perror("signed output data"); + Fclose(op); + op = NULL; + goto jleave; + } + rewind(op); +jleave: + NYD_LEAVE; + return op; +} + +FL FILE * +smime_encrypt_assemble(FILE *hp, FILE *yp) +{ + FILE *op; + int c, lastc = EOF; + NYD_ENTER; + + if ((op = Ftmp(NULL, "smimee", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) == + NULL) { + perror("tempfile"); + goto jleave; + } + + while ((c = getc(hp)) != EOF) { + if (c == '\n' && lastc == '\n') + break; + putc(c, op); + lastc = c; + } + + fprintf(op, "Content-Type: application/x-pkcs7-mime; name=\"smime.p7m\"\n" + "Content-Transfer-Encoding: base64\n" + "Content-Disposition: attachment; filename=\"smime.p7m\"\n\n"); + while ((c = getc(yp)) != EOF) { + if (c == '-') { + while ((c = getc(yp)) != EOF && c != '\n'); + continue; + } + putc(c, op); + } + + Fclose(hp); + Fclose(yp); + + fflush(op); + if (ferror(op)) { + perror("encrypted output data"); + Fclose(op); + op = NULL; + goto jleave; + } + rewind(op); +jleave: + NYD_LEAVE; + return op; +} + +FL struct message * +smime_decrypt_assemble(struct message *m, FILE *hp, FILE *bp) +{ + ui32_t lastnl = 0; + int binary = 0; + char *buf = NULL; + size_t bufsize = 0, buflen, cnt; + long lines = 0, octets = 0; + struct message *x; + off_t offset; + NYD_ENTER; + + x = salloc(sizeof *x); + *x = *m; + fflush(mb.mb_otf); + fseek(mb.mb_otf, 0L, SEEK_END); + offset = ftell(mb.mb_otf); + + cnt = fsize(hp); + while (fgetline(&buf, &bufsize, &cnt, &buflen, hp, 0) != NULL) { + char const *cp; + if (buf[0] == '\n') + break; + if ((cp = thisfield(buf, "content-transfer-encoding")) != NULL) + if (!ascncasecmp(cp, "binary", 7)) + binary = 1; + fwrite(buf, sizeof *buf, buflen, mb.mb_otf); + octets += buflen; + ++lines; + } + + octets += mkdate(mb.mb_otf, "X-Decoding-Date"); + ++lines; + + cnt = fsize(bp); + while (fgetline(&buf, &bufsize, &cnt, &buflen, bp, 0) != NULL) { + lines++; + if (!binary && buf[buflen - 1] == '\n' && buf[buflen - 2] == '\r') + buf[--buflen - 1] = '\n'; + fwrite(buf, sizeof *buf, buflen, mb.mb_otf); + octets += buflen; + if (buf[0] == '\n') + ++lastnl; + else if (buf[buflen - 1] == '\n') + lastnl = 1; + else + lastnl = 0; + } + + while (!binary && lastnl < 2) { + putc('\n', mb.mb_otf); + ++lines; + ++octets; + ++lastnl; + } + + Fclose(hp); + Fclose(bp); + free(buf); + + fflush(mb.mb_otf); + if (ferror(mb.mb_otf)) { + perror("decrypted output data"); + x = NULL; + goto jleave; + } + x->m_size = x->m_xsize = octets; + x->m_lines = x->m_xlines = lines; + x->m_block = mailx_blockof(offset); + x->m_offset = mailx_offsetof(offset); +jleave: + NYD_LEAVE; + return x; +} + +FL int +ccertsave(void *v) +{ + int *ip, *msgvec, val; + char *file = NULL, *str = v; + FILE *fp; + bool_t f; + NYD_ENTER; + + msgvec = salloc((msgCount + 2) * sizeof *msgvec); + val = 1; + + if ((file = laststring(str, &f, 1)) == NULL) { + fprintf(stderr, "No file to save certificate given.\n"); + goto jleave; + } + if (!f) { + *msgvec = first(0, MMNORM); + if (*msgvec == 0) { + if (inhook) + val = 0; + else + fprintf(stderr, "No messages to get certificates from.\n"); + goto jleave; + } + msgvec[1] = 0; + } else if (getmsglist(str, msgvec, 0) < 0) + goto jleave; + + if (*msgvec == 0) { + if (inhook) + val = 0; + else + fprintf(stderr, "No applicable messages.\n"); + goto jleave; + } + + if ((fp = Fopen(file, "a")) == NULL) { + perror(file); + goto jleave; + } + for (val = 0, ip = msgvec; + *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount); ++ip) + if (smime_certsave(&message[*ip - 1], *ip, fp) != OKAY) + val = 1; + Fclose(fp); + + if (val == 0) + printf("Certificate(s) saved.\n"); +jleave: + NYD_LEAVE; + return val; +} + +FL enum okay +rfc2595_hostname_match(char const *host, char const *pattern) +{ + enum okay rv; + NYD_ENTER; + + if (pattern[0] == '*' && pattern[1] == '.') { + ++pattern; + while (*host && *host != '.') + ++host; + } + rv = !asccasecmp(host, pattern) ? OKAY : STOP; + NYD_LEAVE; + return rv; +} +#endif /* HAVE_SSL */ + +/* vim:set fenc=utf-8:s-it-mode */ -- 2.11.4.GIT