chiark / gitweb /
rsa: Do not do validity checks at runtime (in privcache load)
[secnet.git] / rsa.c
1 /*
2  * rsa.c: implementation of RSA with PKCS#1 padding
3  */
4 /*
5  * This file is Free Software.  It was originally written for secnet.
6  *
7  * Copyright 1995-2003 Stephen Early
8  * Copyright 2002-2014 Ian Jackson
9  * Copyright 2001      Simon Tatham
10  * Copyright 2013      Mark Wooding
11  *
12  * You may redistribute secnet as a whole and/or modify it under the
13  * terms of the GNU General Public License as published by the Free
14  * Software Foundation; either version 3, or (at your option) any
15  * later version.
16  *
17  * You may redistribute this file and/or modify it under the terms of
18  * the GNU General Public License as published by the Free Software
19  * Foundation; either version 2, or (at your option) any later
20  * version.
21  *
22  * This software is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this software; if not, see
29  * https://www.gnu.org/licenses/gpl.html.
30  */
31
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <gmp.h>
36 #include "secnet.h"
37 #include "util.h"
38 #include "unaligned.h"
39
40 #define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
41
42 #define mpp(s,n) do { char *p = mpz_get_str(NULL,16,n); printf("%s 0x%sL\n", s, p); free(p); } while (0)
43
44 struct rsacommon {
45     uint8_t *hashbuf;
46 };
47
48 struct rsapriv {
49     closure_t cl;
50     struct sigprivkey_if ops;
51     struct cloc loc;
52     struct rsacommon common;
53     MP_INT n;
54     MP_INT p, dp;
55     MP_INT q, dq;
56     MP_INT w;
57 };
58 struct rsapub {
59     closure_t cl;
60     struct sigpubkey_if ops;
61     struct cloc loc;
62     struct rsacommon common;
63     MP_INT e;
64     MP_INT n;
65 };
66 /* Sign data. NB data must be smaller than modulus */
67
68 #define RSA_MAX_MODBYTES 2048
69 /* The largest modulus I've seen is 15360 bits, which works out at 1920
70  * bytes.  Using keys this big is quite implausible, but it doesn't cost us
71  * much to support them.
72  */
73
74 static const char *hexchars="0123456789abcdef";
75
76 static void rsa_sethash(struct rsacommon *c, struct hash_if *hash,
77                         const struct hash_if **in_ops)
78 {
79     free(c->hashbuf);
80     c->hashbuf=safe_malloc(hash->hlen, "generate_msg");
81     *in_ops=hash;
82 }
83 static void rsa_pub_sethash(void *sst, struct hash_if *hash)
84 {
85     struct rsapub *st=sst;
86     rsa_sethash(&st->common, hash, &st->ops.hash);
87 }
88 static void rsa_priv_sethash(void *sst, struct hash_if *hash)
89 {
90     struct rsapriv *st=sst;
91     rsa_sethash(&st->common, hash, &st->ops.hash);
92 }
93 static void rsacommon_dispose(struct rsacommon *c)
94 {
95     free(c->hashbuf);
96 }
97
98 static void emsa_pkcs1(MP_INT *n, MP_INT *m,
99                        const uint8_t *data, int32_t datalen)
100 {
101     char buff[2*RSA_MAX_MODBYTES + 1];
102     int msize, i;
103
104     /* RSA PKCS#1 v1.5 signature padding:
105      *
106      * <------------ msize hex digits ---------->
107      *
108      * 00 01 ff ff .... ff ff 00 vv vv vv .... vv
109      *
110      *                           <--- datalen -->
111      *                                 bytes
112      *                         = datalen*2 hex digits
113      *
114      * NB that according to PKCS#1 v1.5 we're supposed to include a
115      * hash function OID in the data.  We don't do that (because we
116      * don't have the hash function OID to hand here), thus violating
117      * the spec in a way that affects interop but not security.
118      *
119      * -iwj 17.9.2002
120      */
121
122     msize=mpz_sizeinbase(n, 16);
123
124     if (datalen*2+6>=msize) {
125         fatal("rsa: message too big");
126     }
127
128     strcpy(buff,"0001");
129
130     for (i=0; i<datalen; i++) {
131         buff[msize+(-datalen+i)*2]=hexchars[(data[i]&0xf0)>>4];
132         buff[msize+(-datalen+i)*2+1]=hexchars[data[i]&0xf];
133     }
134     
135     buff[msize-datalen*2-2]= '0';
136     buff[msize-datalen*2-1]= '0';
137  
138     for (i=4; i<msize-datalen*2-2; i++)
139        buff[i]='f';
140
141     buff[msize]=0;
142
143     mpz_set_str(m, buff, 16);
144 }
145
146 static bool_t rsa_sign(void *sst, uint8_t *data, int32_t datalen,
147                        struct buffer_if *msg)
148 {
149     struct rsapriv *st=sst;
150     MP_INT a, b, u, v, tmp, tmp2;
151     string_t signature = 0;
152     bool_t ok;
153
154     mpz_init(&a);
155     mpz_init(&b);
156
157     hash_hash(st->ops.hash,data,datalen,st->common.hashbuf);
158     /* Construct the message representative. */
159     emsa_pkcs1(&st->n, &a, st->common.hashbuf, st->ops.hash->hlen);
160
161     /*
162      * Produce an RSA signature (a^d mod n) using the Chinese
163      * Remainder Theorem. We compute:
164      * 
165      *   u = a^dp mod p    (== a^d mod p, since dp == d mod (p-1))
166      *   v = a^dq mod q    (== a^d mod q, similarly)
167      * 
168      * We also know w == iqmp * q, which has the property that w ==
169      * 0 mod q and w == 1 mod p. So (1-w) has the reverse property
170      * (congruent to 0 mod p and to 1 mod q). Hence we now compute
171      * 
172      *   b = w * u + (1-w) * v
173      *     = w * (u-v) + v
174      * 
175      * so that b is congruent to a^d both mod p and mod q. Hence b,
176      * reduced mod n, is the required signature.
177      */
178     mpz_init(&tmp);
179     mpz_init(&tmp2);
180     mpz_init(&u);
181     mpz_init(&v);
182
183     mpz_powm_sec(&u, &a, &st->dp, &st->p);
184     mpz_powm_sec(&v, &a, &st->dq, &st->q);
185     mpz_sub(&tmp, &u, &v);
186     mpz_mul(&tmp2, &tmp, &st->w);
187     mpz_add(&tmp, &tmp2, &v);
188     mpz_mod(&b, &tmp, &st->n);
189
190     mpz_clear(&tmp);
191     mpz_clear(&tmp2);
192     mpz_clear(&u);
193     mpz_clear(&v);
194
195     signature=write_mpstring(&b);
196
197     uint8_t *op = buf_append(msg,2);
198     if (!op) { ok=False; goto out; }
199     size_t l = strlen(signature);
200     assert(l < 65536);
201     put_uint16(op, l);
202     op = buf_append(msg,l);
203     if (!op) { ok=False; goto out; }
204     memcpy(op, signature, l);
205
206     ok = True;
207
208  out:
209     free(signature);
210     mpz_clear(&b);
211     mpz_clear(&a);
212     return ok;
213 }
214
215 static bool_t rsa_sig_unpick(void *sst, struct buffer_if *msg,
216                              struct alg_msg_data *sig)
217 {
218     uint8_t *lp = buf_unprepend(msg, 2);
219     if (!lp) return False;
220     sig->len = get_uint16(lp);
221     sig->start = buf_unprepend(msg, sig->len);
222     if (!sig->start) return False;
223
224     /* In `rsa_sig_check' below, we assume that we can write a nul
225      * terminator following the signature.  Make sure there's enough space.
226      */
227     if (msg->start >= msg->base + msg->alloclen)
228         return False;
229
230     return True;
231 }
232
233 static sig_checksig_fn rsa_sig_check;
234 static bool_t rsa_sig_check(void *sst, uint8_t *data, int32_t datalen,
235                             const struct alg_msg_data *sig)
236 {
237     struct rsapub *st=sst;
238     MP_INT a, b, c;
239     bool_t ok;
240
241     mpz_init(&a);
242     mpz_init(&b);
243     mpz_init(&c);
244
245     hash_hash(st->ops.hash,data,datalen,st->common.hashbuf);
246     emsa_pkcs1(&st->n, &a, st->common.hashbuf, st->ops.hash->hlen);
247
248     /* Terminate signature with a '0' - already checked that this will fit */
249     int save = sig->start[sig->len];
250     sig->start[sig->len] = 0;
251     mpz_set_str(&b, sig->start, 16);
252     sig->start[sig->len] = save;
253
254     mpz_powm(&c, &b, &st->e, &st->n);
255
256     ok=(mpz_cmp(&a, &c)==0);
257
258     mpz_clear(&c);
259     mpz_clear(&b);
260     mpz_clear(&a);
261
262     return ok;
263 }
264
265 static void rsapub_dispose(void *sst) {
266     struct rsapub *st=sst;
267
268     mpz_clear(&st->e);
269     mpz_clear(&st->n);
270     rsacommon_dispose(&st->common);
271     free(st);
272 }
273
274 static list_t *rsapub_apply(closure_t *self, struct cloc loc, dict_t *context,
275                             list_t *args)
276 {
277     struct rsapub *st;
278     item_t *i;
279     string_t e,n;
280
281     NEW(st);
282     st->cl.description="rsapub";
283     st->cl.type=CL_SIGPUBKEY;
284     st->cl.apply=NULL;
285     st->cl.interface=&st->ops;
286     st->ops.st=st;
287     st->ops.sethash=rsa_pub_sethash;
288     st->common.hashbuf=NULL;
289     st->ops.unpick=rsa_sig_unpick;
290     st->ops.check=rsa_sig_check;
291     st->ops.hash=0;
292     st->ops.dispose=rsapub_dispose;
293     st->loc=loc;
294
295     i=list_elem(args,0);
296     if (i) {
297         if (i->type!=t_string) {
298             cfgfatal(i->loc,"rsa-public","first argument must be a string\n");
299         }
300         e=i->data.string;
301         if (mpz_init_set_str(&st->e,e,10)!=0) {
302             cfgfatal(i->loc,"rsa-public","encryption key \"%s\" is not a "
303                      "decimal number string\n",e);
304         }
305     } else {
306         cfgfatal(loc,"rsa-public","you must provide an encryption key\n");
307     }
308     if (mpz_sizeinbase(&st->e, 256) > RSA_MAX_MODBYTES) {
309         cfgfatal(loc, "rsa-public", "implausibly large public exponent\n");
310     }
311     
312     i=list_elem(args,1);
313     if (i) {
314         if (i->type!=t_string) {
315             cfgfatal(i->loc,"rsa-public","second argument must be a string\n");
316         }
317         n=i->data.string;
318         if (mpz_init_set_str(&st->n,n,10)!=0) {
319             cfgfatal(i->loc,"rsa-public","modulus \"%s\" is not a decimal "
320                      "number string\n",n);
321         }
322     } else {
323         cfgfatal(loc,"rsa-public","you must provide a modulus\n");
324     }
325     if (mpz_sizeinbase(&st->n, 256) > RSA_MAX_MODBYTES) {
326         cfgfatal(loc, "rsa-public", "implausibly large modulus\n");
327     }
328     return new_closure(&st->cl);
329 }
330
331 struct rsapriv_load_ctx {
332     void (*verror)(struct rsapriv_load_ctx *l,
333                    FILE *maybe_f, bool_t unsup,
334                    const char *message, va_list args);
335     bool_t (*postreadcheck)(struct rsapriv_load_ctx *l, FILE *f);
336     union {
337         struct {
338             struct cloc loc;
339         } apply;
340         struct {
341             struct log_if *log;
342         } tryload;
343     } u;
344 };
345
346 #define LDFATAL(...)      ({ load_error(l,0,0,__VA_ARGS__); goto error_out; })
347 #define LDUNSUP(...)      ({ load_error(l,0,1,__VA_ARGS__); goto error_out; })
348 #define LDFATAL_FILE(...) ({ load_error(l,f,0,__VA_ARGS__); goto error_out; })
349 #define LDUNSUP_FILE(...) ({ load_error(l,f,1,__VA_ARGS__); goto error_out; })
350 #define FREE(b)                ({ free((b)); (b)=0; })
351 #define KEYFILE_GET(is)   ({                                    \
352         uint##is##_t keyfile_get_tmp=keyfile_get_##is(l,f);     \
353         if (!l->postreadcheck(l,f)) goto error_out;             \
354         keyfile_get_tmp;                                        \
355     })
356
357 static uint32_t keyfile_get_32(struct rsapriv_load_ctx *l, FILE *f)
358 {
359     uint32_t r;
360     r=fgetc(f)<<24;
361     r|=fgetc(f)<<16;
362     r|=fgetc(f)<<8;
363     r|=fgetc(f);
364     return r;
365 }
366
367 static uint16_t keyfile_get_16(struct rsapriv_load_ctx *l, FILE *f)
368 {
369     uint16_t r;
370     r=fgetc(f)<<8;
371     r|=fgetc(f);
372     return r;
373 }
374
375 static void load_error(struct rsapriv_load_ctx *l, FILE *maybe_f,
376                        bool_t unsup, const char *fmt, ...)
377 {
378     va_list al;
379     va_start(al,fmt);
380     l->verror(l,maybe_f,unsup,fmt,al);
381     va_end(al);
382 }
383
384 static void rsapriv_dispose(void *sst)
385 {
386     struct rsapriv *st=sst;
387     mpz_clear(&st->n);
388     mpz_clear(&st->p); mpz_clear(&st->dp);
389     mpz_clear(&st->q); mpz_clear(&st->dq);
390     mpz_clear(&st->w);
391     rsacommon_dispose(&st->common);
392     free(st);
393 }
394
395 static struct rsapriv *rsa_loadpriv_core(struct rsapriv_load_ctx *l,
396                                          FILE *f, struct cloc loc,
397                                          bool_t do_validity_check)
398 {
399     struct rsapriv *st=0;
400     long length;
401     uint8_t *b=0, *c=0;
402     int cipher_type;
403     MP_INT e,d,iqmp,tmp,tmp2,tmp3;
404     bool_t valid;
405
406     mpz_init(&e);
407     mpz_init(&d);
408     mpz_init(&iqmp);
409     mpz_init(&tmp);
410     mpz_init(&tmp2);
411     mpz_init(&tmp3);
412
413     NEW(st);
414     st->cl.description="rsapriv";
415     st->cl.type=CL_SIGPRIVKEY;
416     st->cl.apply=NULL;
417     st->cl.interface=&st->ops;
418     st->ops.st=st;
419     st->ops.sethash=rsa_priv_sethash;
420     st->common.hashbuf=NULL;
421     st->ops.sign=rsa_sign;
422     st->ops.hash=0;
423     st->ops.dispose=rsapriv_dispose;
424     st->loc=loc;
425     mpz_init(&st->n);
426     mpz_init(&st->q);
427     mpz_init(&st->p);
428     mpz_init(&st->dp);
429     mpz_init(&st->dq);
430     mpz_init(&st->w);
431
432     if (!f) {
433         assert(just_check_config);
434         goto assume_valid;
435     }
436
437     /* Check that the ID string is correct */
438     length=strlen(AUTHFILE_ID_STRING)+1;
439     b=safe_malloc(length,"rsapriv_apply");
440     if (fread(b,length,1,f)!=1 || memcmp(b,AUTHFILE_ID_STRING,length)!=0) {
441         LDUNSUP_FILE("failed to read magic ID"
442                      " string from SSH1 private keyfile\n");
443     }
444     FREE(b);
445
446     cipher_type=fgetc(f);
447     KEYFILE_GET(32); /* "Reserved data" */
448     if (cipher_type != 0) {
449         LDUNSUP("we don't support encrypted keyfiles\n");
450     }
451
452     /* Read the public key */
453     KEYFILE_GET(32); /* Not sure what this is */
454     length=(KEYFILE_GET(16)+7)/8;
455     if (length>RSA_MAX_MODBYTES) {
456         LDFATAL("implausible length %ld for modulus\n",
457                  length);
458     }
459     b=safe_malloc(length,"rsapriv_apply");
460     if (fread(b,length,1,f) != 1) {
461         LDFATAL_FILE("error reading modulus\n");
462     }
463     read_mpbin(&st->n,b,length);
464     FREE(b);
465     length=(KEYFILE_GET(16)+7)/8;
466     if (length>RSA_MAX_MODBYTES) {
467         LDFATAL("implausible length %ld for e\n",length);
468     }
469     b=safe_malloc(length,"rsapriv_apply");
470     if (fread(b,length,1,f)!=1) {
471         LDFATAL_FILE("error reading e\n");
472     }
473     read_mpbin(&e,b,length);
474     FREE(b);
475     
476     length=KEYFILE_GET(32);
477     if (length>1024) {
478         LDFATAL("implausibly long (%ld) key comment\n",
479                  length);
480     }
481     c=safe_malloc(length+1,"rsapriv_apply");
482     if (fread(c,length,1,f)!=1) {
483         LDFATAL_FILE("error reading key comment\n");
484     }
485     c[length]=0;
486
487     /* Check that the next two pairs of characters are identical - the
488        keyfile is not encrypted, so they should be */
489
490     if (KEYFILE_GET(16) != KEYFILE_GET(16)) {
491         LDFATAL("corrupt keyfile\n");
492     }
493
494     /* Read d */
495     length=(KEYFILE_GET(16)+7)/8;
496     if (length>RSA_MAX_MODBYTES) {
497         LDFATAL("implausibly long (%ld) decryption key\n",
498                  length);
499     }
500     b=safe_malloc(length,"rsapriv_apply");
501     if (fread(b,length,1,f)!=1) {
502         LDFATAL_FILE("error reading decryption key\n");
503     }
504     read_mpbin(&d,b,length);
505     FREE(b);
506     /* Read iqmp (inverse of q mod p) */
507     length=(KEYFILE_GET(16)+7)/8;
508     if (length>RSA_MAX_MODBYTES) {
509         LDFATAL("implausibly long (%ld)"
510                  " iqmp auxiliary value\n", length);
511     }
512     b=safe_malloc(length,"rsapriv_apply");
513     if (fread(b,length,1,f)!=1) {
514         LDFATAL_FILE("error reading decryption key\n");
515     }
516     read_mpbin(&iqmp,b,length);
517     FREE(b);
518     /* Read q (the smaller of the two primes) */
519     length=(KEYFILE_GET(16)+7)/8;
520     if (length>RSA_MAX_MODBYTES) {
521         LDFATAL("implausibly long (%ld) q value\n",
522                  length);
523     }
524     b=safe_malloc(length,"rsapriv_apply");
525     if (fread(b,length,1,f)!=1) {
526         LDFATAL_FILE("error reading q value\n");
527     }
528     read_mpbin(&st->q,b,length);
529     FREE(b);
530     /* Read p (the larger of the two primes) */
531     length=(KEYFILE_GET(16)+7)/8;
532     if (length>RSA_MAX_MODBYTES) {
533         LDFATAL("implausibly long (%ld) p value\n",
534                  length);
535     }
536     b=safe_malloc(length,"rsapriv_apply");
537     if (fread(b,length,1,f)!=1) {
538         LDFATAL_FILE("error reading p value\n");
539     }
540     read_mpbin(&st->p,b,length);
541     FREE(b);
542     
543     if (ferror(f)) {
544         fatal_perror("rsa-private (%s:%d): ferror",loc.file,loc.line);
545     }
546
547     /*
548      * Now verify the validity of the key, and set up the auxiliary
549      * values for fast CRT signing.
550      */
551     valid=False;
552     if (do_validity_check) {
553         /* Verify that p*q is equal to n. */
554         mpz_mul(&tmp, &st->p, &st->q);
555         if (mpz_cmp(&tmp, &st->n) != 0)
556             goto done_checks;
557
558         /*
559          * Verify that d*e is congruent to 1 mod (p-1), and mod
560          * (q-1). This is equivalent to it being congruent to 1 mod
561          * lambda(n) = lcm(p-1,q-1).  The usual `textbook' condition,
562          * that d e == 1 (mod (p-1)(q-1)) is sufficient, but not
563          * actually necessary.
564          */
565         mpz_mul(&tmp, &d, &e);
566         mpz_sub_ui(&tmp2, &st->p, 1);
567         mpz_mod(&tmp3, &tmp, &tmp2);
568         if (mpz_cmp_si(&tmp3, 1) != 0)
569             goto done_checks;
570         mpz_sub_ui(&tmp2, &st->q, 1);
571         mpz_mod(&tmp3, &tmp, &tmp2);
572         if (mpz_cmp_si(&tmp3, 1) != 0)
573             goto done_checks;
574
575         /* Verify that q*iqmp is congruent to 1 mod p. */
576         mpz_mul(&tmp, &st->q, &iqmp);
577         mpz_mod(&tmp2, &tmp, &st->p);
578         if (mpz_cmp_si(&tmp2, 1) != 0)
579             goto done_checks;
580     }
581     /* Now we know the key is valid (or we don't care). */
582     valid = True;
583     
584     /*
585      * Now we compute auxiliary values dp, dq and w to allow us
586      * to use the CRT optimisation when signing.
587      * 
588      *   dp == d mod (p-1)      so that a^dp == a^d mod p, for all a
589      *   dq == d mod (q-1)      similarly mod q
590      *   w == iqmp * q          so that w == 0 mod q, and w == 1 mod p
591      */
592     mpz_sub_ui(&tmp, &st->p, 1);
593     mpz_mod(&st->dp, &d, &tmp);
594     mpz_sub_ui(&tmp, &st->q, 1);
595     mpz_mod(&st->dq, &d, &tmp);
596     mpz_mul(&st->w, &iqmp, &st->q);
597     
598 done_checks:
599     if (!valid) {
600         LDFATAL("file does not contain a "
601                  "valid RSA key!\n");
602     }
603
604 assume_valid:
605 out:
606     mpz_clear(&tmp);
607     mpz_clear(&tmp2);
608     mpz_clear(&tmp3);
609
610     FREE(b);
611     FREE(c);
612     mpz_clear(&e);
613     mpz_clear(&d);
614     mpz_clear(&iqmp);
615
616     return st;
617
618 error_out:
619     if (st) rsapriv_dispose(st);
620     st=0;
621     goto out;
622 }
623
624 FORMAT(printf,4,0)
625 static void verror_tryload(struct rsapriv_load_ctx *l,
626                            FILE *maybe_f, bool_t unsup,
627                            const char *message, va_list args)
628 {
629     int class=unsup ? M_DEBUG : M_ERR;
630     slilog_part(l->u.tryload.log,class,"rsa1priv load: ");
631     vslilog(l->u.tryload.log,class,message,args);
632 }
633
634 static bool_t postreadcheck_tryload(struct rsapriv_load_ctx *l, FILE *f)
635 {
636     assert(!ferror(f));
637     if (feof(f)) { load_error(l,0,0,"eof mid-integer"); return False; }
638     return True;
639 }
640
641 bool_t rsa1_loadpriv(const struct sigscheme_info *algo,
642                      struct buffer_if *privkeydata,
643                      struct sigprivkey_if **sigpriv_r,
644                      struct log_if *log)
645 {
646     FILE *f=0;
647     struct rsapriv *st=0;
648
649     f=fmemopen(privkeydata->start,privkeydata->size,"r");
650     if (!f) {
651         slilog(log,M_ERR,"failed to fmemopen private key file\n");
652         goto error_out;
653     }
654
655     struct cloc loc;
656     loc.file="dynamically loaded";
657     loc.line=0;
658
659     struct rsapriv_load_ctx l[1];
660     l->verror=verror_tryload;
661     l->postreadcheck=postreadcheck_tryload;
662     l->u.tryload.log=log;
663
664     st=rsa_loadpriv_core(l,f,loc,False);
665     if (!st) goto error_out;
666     goto out;
667
668  error_out:
669     if (st) { free(st); st=0; }
670  out:
671     if (f) fclose(f);
672     if (!st) return False;
673     *sigpriv_r=&st->ops;
674     return True;
675 }
676
677 static void verror_cfgfatal(struct rsapriv_load_ctx *l,
678                             FILE *maybe_f, bool_t unsup,
679                             const char *message, va_list args)
680 {
681     vcfgfatal_maybefile(maybe_f,l->u.apply.loc,"rsa-private",message,args);
682 }
683
684 static bool_t postreadcheck_apply(struct rsapriv_load_ctx *l, FILE *f)
685 {
686     cfgfile_postreadcheck(l->u.apply.loc,f);
687     return True;
688 }
689
690 static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context,
691                              list_t *args)
692 {
693     struct rsapriv *st;
694     item_t *i;
695     cstring_t filename;
696     FILE *f;
697     struct rsapriv_load_ctx l[1];
698
699     l->verror=verror_cfgfatal;
700     l->postreadcheck=postreadcheck_apply;
701     l->u.apply.loc=loc;
702
703     /* Argument is filename pointing to SSH1 private key file */
704     i=list_elem(args,0);
705     if (i) {
706         if (i->type!=t_string) {
707             cfgfatal(i->loc,"rsa-private","first argument must be a string\n");
708         }
709         filename=i->data.string;
710     } else {
711         filename=NULL; /* Make compiler happy */
712         cfgfatal(i->loc,"rsa-private","you must provide a filename\n");
713     }
714
715     f=fopen(filename,"rb");
716     if (!f) {
717         if (just_check_config) {
718             Message(M_WARNING,"rsa-private (%s:%d): cannot open keyfile "
719                     "\"%s\"; assuming it's valid while we check the "
720                     "rest of the configuration\n",loc.file,loc.line,filename);
721         } else {
722             fatal_perror("rsa-private (%s:%d): cannot open file \"%s\"",
723                          loc.file,loc.line,filename);
724         }
725     }
726
727     bool_t do_validity_check=True;
728     i=list_elem(args,1);
729     if (i && i->type==t_bool && i->data.bool==False) {
730         Message(M_INFO,"rsa-private (%s:%d): skipping RSA key validity "
731                 "check\n",loc.file,loc.line);
732         do_validity_check=False;
733     }
734
735     st=rsa_loadpriv_core(l,f,loc,do_validity_check);
736     fclose(f);
737     return new_closure(&st->cl);
738 }
739
740 void rsa_module(dict_t *dict)
741 {
742     add_closure(dict,"rsa-private",rsapriv_apply);
743     add_closure(dict,"rsa-public",rsapub_apply);
744 }