1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Generic SSL / S/MIME commands.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
9 * Gunnar Ritter. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Gunnar Ritter
22 * and his contributors.
23 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 #ifndef HAVE_AMALGAMATION
48 struct ssl_verify_levels
{
49 char const sv_name
[8];
50 enum ssl_verify_level sv_level
;
53 /* Supported SSL/TLS verification methods: update manual on change! */
54 static struct ssl_verify_levels
const _ssl_verify_levels
[] = {
55 {"strict", SSL_VERIFY_STRICT
},
56 {"ask", SSL_VERIFY_ASK
},
57 {"warn", SSL_VERIFY_WARN
},
58 {"ignore", SSL_VERIFY_IGNORE
}
62 ssl_set_verify_level(struct url
const *urlp
)
68 ssl_verify_level
= SSL_VERIFY_ASK
;
69 cp
= xok_vlook(ssl_verify
, urlp
, OXM_ALL
);
72 for (i
= 0; i
< NELEM(_ssl_verify_levels
); ++i
)
73 if (!asccasecmp(_ssl_verify_levels
[i
].sv_name
, cp
)) {
74 ssl_verify_level
= _ssl_verify_levels
[i
].sv_level
;
77 n_err(_("Invalid value of *ssl-verify*: %s\n"), cp
);
84 ssl_verify_decide(void)
89 switch (ssl_verify_level
) {
90 case SSL_VERIFY_STRICT
:
94 rv
= getapproval(NULL
, FAL0
) ? OKAY
: STOP
;
97 case SSL_VERIFY_IGNORE
:
106 smime_split(FILE *ip
, FILE **hp
, FILE **bp
, long xcount
, int keep
)
109 struct myline
*ml_next
;
111 char ml_buf
[VFIELD_SIZE(0)];
114 size_t bufsize
, buflen
, cnt
;
119 if ((*hp
= Ftmp(NULL
, "smimeh", OF_RDWR
| OF_UNLINK
| OF_REGISTER
, 0600)) ==
122 if ((*bp
= Ftmp(NULL
, "smimeb", OF_RDWR
| OF_UNLINK
| OF_REGISTER
, 0600)) ==
126 n_perr(_("tempfile"), 0);
131 buf
= smalloc(bufsize
= LINESIZE
);
132 cnt
= (xcount
< 0) ? fsize(ip
) : xcount
;
134 while (fgetline(&buf
, &bufsize
, &cnt
, &buflen
, ip
, 0) != NULL
&&
136 if (!ascncasecmp(buf
, "content-", 8)) {
138 fputs("X-Encoded-", *hp
);
140 struct myline
*ml
= smalloc(sizeof *ml
-
141 VFIELD_SIZEOF(struct myline
, ml_buf
) + buflen
+1);
149 memcpy(ml
->ml_buf
, buf
, buflen
+1);
151 fwrite(buf
, sizeof *buf
, buflen
, *hp
);
156 fgetline(&buf
, &bufsize
, &cnt
, &buflen
, ip
, 0);
160 fwrite(buf
, sizeof *buf
, buflen
, *hp
);
164 while (head
!= NULL
) {
165 fwrite(head
->ml_buf
, sizeof *head
->ml_buf
, head
->ml_len
, *bp
);
167 head
= head
->ml_next
;
171 while (fgetline(&buf
, &bufsize
, &cnt
, &buflen
, ip
, 0) != NULL
)
172 fwrite(buf
, sizeof *buf
, buflen
, *bp
);
183 smime_sign_assemble(FILE *hp
, FILE *bp
, FILE *sp
, char const *message_digest
)
190 if ((op
= Ftmp(NULL
, "smimea", OF_RDWR
| OF_UNLINK
| OF_REGISTER
, 0600)) ==
192 n_perr(_("tempfile"), 0);
196 while ((c
= getc(hp
)) != EOF
) {
197 if (c
== '\n' && lastc
== '\n')
203 boundary
= mime_param_boundary_create();
204 fprintf(op
, "Content-Type: multipart/signed;\n"
205 " protocol=\"application/pkcs7-signature\"; micalg=%s;\n"
206 " boundary=\"%s\"\n\n", message_digest
, boundary
);
207 fprintf(op
, "This is a S/MIME signed message.\n\n--%s\n", boundary
);
208 while ((c
= getc(bp
)) != EOF
)
211 fprintf(op
, "\n--%s\n", boundary
);
212 fputs("Content-Type: application/pkcs7-signature; name=\"smime.p7s\"\n"
213 "Content-Transfer-Encoding: base64\n"
214 "Content-Disposition: attachment; filename=\"smime.p7s\"\n\n", op
);
215 while ((c
= getc(sp
)) != EOF
) {
217 while ((c
= getc(sp
)) != EOF
&& c
!= '\n');
223 fprintf(op
, "\n--%s--\n", boundary
);
231 n_perr(_("signed output data"), 0);
243 smime_encrypt_assemble(FILE *hp
, FILE *yp
)
249 if ((op
= Ftmp(NULL
, "smimee", OF_RDWR
| OF_UNLINK
| OF_REGISTER
, 0600)) ==
251 n_perr(_("tempfile"), 0);
255 while ((c
= getc(hp
)) != EOF
) {
256 if (c
== '\n' && lastc
== '\n')
262 fprintf(op
, "Content-Type: application/pkcs7-mime; name=\"smime.p7m\"\n"
263 "Content-Transfer-Encoding: base64\n"
264 "Content-Disposition: attachment; filename=\"smime.p7m\"\n\n");
265 while ((c
= getc(yp
)) != EOF
) {
267 while ((c
= getc(yp
)) != EOF
&& c
!= '\n');
278 n_perr(_("encrypted output data"), 0);
290 smime_decrypt_assemble(struct message
*m
, FILE *hp
, FILE *bp
)
295 size_t bufsize
= 0, buflen
, cnt
;
296 long lines
= 0, octets
= 0;
301 x
= salloc(sizeof *x
);
304 fseek(mb
.mb_otf
, 0L, SEEK_END
);
305 offset
= ftell(mb
.mb_otf
);
308 while (fgetline(&buf
, &bufsize
, &cnt
, &buflen
, hp
, 0) != NULL
) {
312 if ((cp
= thisfield(buf
, "content-transfer-encoding")) != NULL
)
313 if (!ascncasecmp(cp
, "binary", 7))
315 fwrite(buf
, sizeof *buf
, buflen
, mb
.mb_otf
);
320 { struct time_current save
= time_current
;
321 time_current_update(&time_current
, TRU1
);
322 octets
+= mkdate(mb
.mb_otf
, "X-Decoding-Date");
328 while (fgetline(&buf
, &bufsize
, &cnt
, &buflen
, bp
, 0) != NULL
) {
330 if (!binary
&& buf
[buflen
- 1] == '\n' && buf
[buflen
- 2] == '\r')
331 buf
[--buflen
- 1] = '\n';
332 fwrite(buf
, sizeof *buf
, buflen
, mb
.mb_otf
);
336 else if (buf
[buflen
- 1] == '\n')
342 while (!binary
&& lastnl
< 2) {
343 putc('\n', mb
.mb_otf
);
354 if (ferror(mb
.mb_otf
)) {
355 n_perr(_("decrypted output data"), 0);
359 x
->m_size
= x
->m_xsize
= octets
;
360 x
->m_lines
= x
->m_xlines
= lines
;
361 x
->m_block
= mailx_blockof(offset
);
362 x
->m_offset
= mailx_offsetof(offset
);
371 int *ip
, *msgvec
, val
;
372 char *file
= NULL
, *str
= v
;
377 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
380 if ((file
= laststring(str
, &f
, TRU1
)) == NULL
||
381 (file
= file_expand(file
)) == NULL
) {
382 n_err(_("No file to save certificate given\n"));
388 *msgvec
= first(0, MMNORM
);
389 } else if (getmsglist(str
, msgvec
, 0) < 0)
392 if (pstate
& PS_HOOK_MASK
)
395 n_err(_("No applicable messages\n"));
399 if ((fp
= Fopen(file
, "a")) == NULL
) {
403 for (val
= 0, ip
= msgvec
;
404 *ip
!= 0 && UICMP(z
, PTR2SIZE(ip
- msgvec
), <, msgCount
); ++ip
)
405 if (smime_certsave(&message
[*ip
- 1], *ip
, fp
) != OKAY
)
410 printf("Certificate(s) saved\n");
417 rfc2595_hostname_match(char const *host
, char const *pattern
)
422 if (pattern
[0] == '*' && pattern
[1] == '.') {
424 while (*host
&& *host
!= '.')
427 rv
= !asccasecmp(host
, pattern
) ? OKAY
: STOP
;
431 #endif /* HAVE_SSL */