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 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
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
< n_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
[n_VFIELD_SIZE(0)];
114 size_t bufsize
, buflen
, cnt
;
119 if ((*hp
= Ftmp(NULL
, "smimeh", OF_RDWR
| OF_UNLINK
| OF_REGISTER
)) == NULL
)
121 if ((*bp
= Ftmp(NULL
, "smimeb", OF_RDWR
| OF_UNLINK
| OF_REGISTER
)) ==NULL
) {
124 n_perr(_("tempfile"), 0);
129 buf
= smalloc(bufsize
= LINESIZE
);
130 cnt
= (xcount
< 0) ? fsize(ip
) : xcount
;
132 while (fgetline(&buf
, &bufsize
, &cnt
, &buflen
, ip
, 0) != NULL
&&
134 if (!ascncasecmp(buf
, "content-", 8)) {
136 fputs("X-Encoded-", *hp
);
138 struct myline
*ml
= smalloc(n_VSTRUCT_SIZEOF(struct myline
, ml_buf
147 memcpy(ml
->ml_buf
, buf
, buflen
+1);
149 fwrite(buf
, sizeof *buf
, buflen
, *hp
);
154 fgetline(&buf
, &bufsize
, &cnt
, &buflen
, ip
, 0);
158 fwrite(buf
, sizeof *buf
, buflen
, *hp
);
162 while (head
!= NULL
) {
163 fwrite(head
->ml_buf
, sizeof *head
->ml_buf
, head
->ml_len
, *bp
);
165 head
= head
->ml_next
;
169 while (fgetline(&buf
, &bufsize
, &cnt
, &buflen
, ip
, 0) != NULL
)
170 fwrite(buf
, sizeof *buf
, buflen
, *bp
);
181 smime_sign_assemble(FILE *hp
, FILE *bp
, FILE *sp
, char const *message_digest
)
188 if ((op
= Ftmp(NULL
, "smimea", OF_RDWR
| OF_UNLINK
| OF_REGISTER
)) == NULL
) {
189 n_perr(_("tempfile"), 0);
193 while ((c
= getc(hp
)) != EOF
) {
194 if (c
== '\n' && lastc
== '\n')
200 boundary
= mime_param_boundary_create();
201 fprintf(op
, "Content-Type: multipart/signed;\n"
202 " protocol=\"application/pkcs7-signature\"; micalg=%s;\n"
203 " boundary=\"%s\"\n\n", message_digest
, boundary
);
204 fprintf(op
, "This is a S/MIME signed message.\n\n--%s\n", boundary
);
205 while ((c
= getc(bp
)) != EOF
)
208 fprintf(op
, "\n--%s\n", boundary
);
209 fputs("Content-Type: application/pkcs7-signature; name=\"smime.p7s\"\n"
210 "Content-Transfer-Encoding: base64\n"
211 "Content-Disposition: attachment; filename=\"smime.p7s\"\n"
212 "Content-Description: S/MIME digital signature\n\n", op
);
213 while ((c
= getc(sp
)) != EOF
) {
215 while ((c
= getc(sp
)) != EOF
&& c
!= '\n');
221 fprintf(op
, "\n--%s--\n", boundary
);
229 n_perr(_("signed output data"), 0);
241 smime_encrypt_assemble(FILE *hp
, FILE *yp
)
247 if ((op
= Ftmp(NULL
, "smimee", OF_RDWR
| OF_UNLINK
| OF_REGISTER
)) == NULL
) {
248 n_perr(_("tempfile"), 0);
252 while ((c
= getc(hp
)) != EOF
) {
253 if (c
== '\n' && lastc
== '\n')
259 fputs("Content-Type: application/pkcs7-mime; name=\"smime.p7m\"\n"
260 "Content-Transfer-Encoding: base64\n"
261 "Content-Disposition: attachment; filename=\"smime.p7m\"\n"
262 "Content-Description: S/MIME encrypted message\n\n", op
);
263 while ((c
= getc(yp
)) != EOF
) {
265 while ((c
= getc(yp
)) != EOF
&& c
!= '\n');
276 n_perr(_("encrypted output data"), 0);
288 smime_decrypt_assemble(struct message
*m
, FILE *hp
, FILE *bp
)
293 size_t bufsize
= 0, buflen
, cnt
;
294 long lines
= 0, octets
= 0;
299 x
= salloc(sizeof *x
);
302 fseek(mb
.mb_otf
, 0L, SEEK_END
);
303 offset
= ftell(mb
.mb_otf
);
306 while (fgetline(&buf
, &bufsize
, &cnt
, &buflen
, hp
, 0) != NULL
) {
310 if ((cp
= thisfield(buf
, "content-transfer-encoding")) != NULL
)
311 if (!ascncasecmp(cp
, "binary", 7))
313 fwrite(buf
, sizeof *buf
, buflen
, mb
.mb_otf
);
318 { struct time_current save
= time_current
;
319 time_current_update(&time_current
, TRU1
);
320 octets
+= mkdate(mb
.mb_otf
, "X-Decoding-Date");
326 while (fgetline(&buf
, &bufsize
, &cnt
, &buflen
, bp
, 0) != NULL
) {
328 if (!binary
&& buf
[buflen
- 1] == '\n' && buf
[buflen
- 2] == '\r')
329 buf
[--buflen
- 1] = '\n';
330 fwrite(buf
, sizeof *buf
, buflen
, mb
.mb_otf
);
334 else if (buf
[buflen
- 1] == '\n')
340 while (!binary
&& lastnl
< 2) {
341 putc('\n', mb
.mb_otf
);
352 if (ferror(mb
.mb_otf
)) {
353 n_perr(_("decrypted output data"), 0);
357 x
->m_size
= x
->m_xsize
= octets
;
358 x
->m_lines
= x
->m_xlines
= lines
;
359 x
->m_block
= mailx_blockof(offset
);
360 x
->m_offset
= mailx_offsetof(offset
);
369 int *ip
, *msgvec
, val
;
370 char *file
= NULL
, *str
= v
;
375 msgvec
= salloc((msgCount
+ 2) * sizeof *msgvec
);
378 if ((file
= laststring(str
, &f
, TRU1
)) == NULL
||
379 (file
= fexpand(file
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
) {
380 n_err(_("No file to save certificate given\n"));
386 *msgvec
= first(0, MMNORM
);
387 } else if (getmsglist(str
, msgvec
, 0) < 0)
390 if (n_pstate
& (n_PS_HOOK_MASK
| n_PS_ROBOT
))
393 n_err(_("No applicable messages\n"));
397 if ((fp
= Fopen(file
, "a")) == NULL
) {
401 for (val
= 0, ip
= msgvec
;
402 *ip
!= 0 && UICMP(z
, PTR2SIZE(ip
- msgvec
), <, msgCount
); ++ip
)
403 if (smime_certsave(&message
[*ip
- 1], *ip
, fp
) != OKAY
)
408 fprintf(n_stdout
, "Certificate(s) saved\n");
415 rfc2595_hostname_match(char const *host
, char const *pattern
)
420 if (pattern
[0] == '*' && pattern
[1] == '.') {
422 while (*host
&& *host
!= '.')
425 rv
= !asccasecmp(host
, pattern
) ? OKAY
: STOP
;
429 #endif /* HAVE_SSL */