2 * Kernel runtime algorithm handling interface
3 * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
5 * $Id: kernel_alg.c,v 1.2 2004-08-02 04:35:33 gerg Exp $
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
30 #include "constants.h"
34 #include "connections.h"
39 #include "kernel_alg.h"
48 * macros/functions for compilation without pluto (eg: spi for manual conns)
52 #define passert(x) assert(x)
53 #define DBG(cond, action) { if (debug) { action ; } }
54 #define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
55 #define log(x, args...) fprintf(stderr, x "\n" , ##args);
58 static struct sadb_alg esp_aalg[SADB_AALG_MAX+1];
59 static struct sadb_alg esp_ealg[SADB_EALG_MAX+1];
60 static int esp_ealg_num=0;
61 static int esp_aalg_num=0;
63 #define ESP_EALG_PRESENT(algo) (((algo)<=SADB_EALG_MAX)&&(esp_ealg[(algo)].sadb_alg_id==(algo)))
64 #define ESP_EALG_FOR_EACH(algo) \
65 for (algo=1; algo <= SADB_EALG_MAX; algo++) \
66 if (ESP_EALG_PRESENT(algo))
67 #define ESP_EALG_FOR_EACH_UPDOWN(algo) \
68 for (algo=SADB_EALG_MAX; algo >0 ; algo--) \
69 if (ESP_EALG_PRESENT(algo))
70 #define ESP_AALG_PRESENT(algo) ((algo<=SADB_AALG_MAX)&&(esp_aalg[(algo)].sadb_alg_id==(algo)))
71 #define ESP_AALG_FOR_EACH(algo) \
72 for (algo=1; algo <= SADB_AALG_MAX; algo++) \
73 if (ESP_AALG_PRESENT(algo))
74 #define ESP_AALG_FOR_EACH_UPDOWN(algo) \
75 for (algo=SADB_AALG_MAX; algo >0 ; algo--) \
76 if (ESP_AALG_PRESENT(algo))
78 static struct sadb_alg *
79 sadb_alg_ptr (int satype, int exttype, int alg_id, int rw)
81 struct sadb_alg *alg_p=NULL;
83 case SADB_EXT_SUPPORTED_AUTH:
84 if (alg_id<=SADB_AALG_MAX)
87 case SADB_EXT_SUPPORTED_ENCRYPT:
88 if (alg_id<=SADB_EALG_MAX)
96 alg_p=(exttype == SADB_EXT_SUPPORTED_ENCRYPT)?
97 &esp_ealg[alg_id] : &esp_aalg[alg_id];
98 /* get for write: increment elem count */
100 (exttype == SADB_EXT_SUPPORTED_ENCRYPT)?
101 esp_ealg_num++ : esp_aalg_num++;
113 const struct sadb_alg *
114 kernel_alg_sadb_alg_get(int satype, int exttype, int alg_id)
116 return sadb_alg_ptr(satype, exttype, alg_id, 0);
119 * Forget previous registration
122 kernel_alg_init(void)
124 DBG(DBG_KLIPS, DBG_log("alg_init():"
126 "memset(%p, 0, %d) ",
127 &esp_aalg, sizeof (esp_aalg),
128 &esp_ealg, sizeof (esp_ealg)));
129 memset (&esp_aalg, 0, sizeof (esp_aalg));
130 memset (&esp_ealg, 0, sizeof (esp_ealg));
131 esp_ealg_num=esp_aalg_num=0;
135 kernel_alg_add(int satype, int exttype, const struct sadb_alg *sadb_alg)
138 struct sadb_alg *alg_p=NULL;
139 int alg_id=sadb_alg->sadb_alg_id;
140 DBG(DBG_KLIPS, DBG_log("kernel_alg_add():"
141 "satype=%d, exttype=%d, alg_id=%d",
142 satype, exttype, sadb_alg->sadb_alg_id));
143 if (!(alg_p=sadb_alg_ptr(satype, exttype, alg_id, 1)))
147 DBG(DBG_KLIPS, DBG_log("kernel_alg_add(): assign *%p=*%p",
157 kernel_alg_esp_enc_ok(int alg_id, unsigned int key_len, struct alg_info_esp *alg_info)
159 struct sadb_alg *alg_p=NULL;
161 * test #1: encrypt algo must be present
163 int ret=ESP_EALG_PRESENT(alg_id);
166 alg_p=&esp_ealg[alg_id];
168 * test #2: if key_len specified, it must be in range
170 if ((key_len) && ((key_len < alg_p->sadb_alg_minbits) ||
171 (key_len > alg_p->sadb_alg_maxbits))) {
172 log ("%s() key_len not in range: alg_id=%d, "
173 "key_len=%d, alg_minbits=%d, alg_maxbits=%d",
176 alg_p->sadb_alg_minbits,
177 alg_p->sadb_alg_maxbits
182 * test #3: if alg_info specified AND strict flag, only
183 * only allow algo iff listed in st->alg_info_esp
185 else if (alg_info && (alg_info->alg_info_flags & ALG_INFO_F_STRICT) ) {
187 struct esp_info *esp_info;
188 ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) {
189 if ((esp_info->esp_ealg_id == alg_id) &&
190 ((esp_info->esp_ealg_keylen==0) || (key_len==0) ||
191 (esp_info->esp_ealg_keylen==key_len))) {
196 log("%s() strict flag and algo not in alg_info: "
198 "key_len=%d, alg_minbits=%d, alg_maxbits=%d",
201 alg_p->sadb_alg_minbits,
202 alg_p->sadb_alg_maxbits
209 DBG_log("kernel_alg_esp_enc_ok(%d,%d): "
211 "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
215 alg_p->sadb_alg_ivlen,
216 alg_p->sadb_alg_minbits,
217 alg_p->sadb_alg_maxbits,
218 alg_p->sadb_alg_reserved,
223 DBG_log("kernel_alg_esp_enc_ok(%d,%d): NO",
231 * Load kernel_alg arrays from /proc
232 * used in manual mode from klips/utils/spi.c
235 kernel_alg_proc_read(void) {
238 int alg_id, ivlen, minbits, maxbits;
239 struct sadb_alg sadb_alg;
242 FILE *fp=fopen("/proc/net/pf_key_supported", "r");
246 while (fgets(buf, sizeof(buf), fp)) {
247 if (buf[0] != ' ') /* skip titles */
249 sscanf(buf, "%d %d %d %d %d %d",
250 &satype, &supp_exttype,
255 case SADB_SATYPE_ESP:
256 switch(supp_exttype) {
257 case SADB_EXT_SUPPORTED_AUTH:
258 case SADB_EXT_SUPPORTED_ENCRYPT:
259 sadb_alg.sadb_alg_id=alg_id;
260 sadb_alg.sadb_alg_ivlen=ivlen;
261 sadb_alg.sadb_alg_minbits=minbits;
262 sadb_alg.sadb_alg_maxbits=maxbits;
263 ret=kernel_alg_add(satype, supp_exttype, &sadb_alg);
264 DBG(DBG_CRYPT, DBG_log("%s() alg_id=%d, "
265 "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
268 sadb_alg.sadb_alg_id,
269 sadb_alg.sadb_alg_ivlen,
270 sadb_alg.sadb_alg_minbits,
271 sadb_alg.sadb_alg_maxbits,
283 * Load kernel_alg arrays pluto's SADB_REGISTER
284 * user by pluto/kernel.c
288 kernel_alg_register_pfkey(void *buf, int buflen)
291 * Trick: one 'type-mangle-able' pointer to
295 const struct sadb_msg *msg;
296 const struct sadb_supported *supported;
297 const struct sadb_ext *ext;
298 const struct sadb_alg *alg;
301 const struct sadb_msg *msg_buf=buf;
305 /* Initialize alg arrays */
307 satype=msg_buf->sadb_msg_satype;
309 msglen=sadb.msg->sadb_msg_len*IPSEC_PFKEYv2_ALIGN;
310 msglen-=sizeof(struct sadb_msg);
311 buflen-=sizeof(struct sadb_msg);
315 int supp_exttype=sadb.supported->sadb_supported_exttype;
317 supp_len=sadb.supported->sadb_supported_len*IPSEC_PFKEYv2_ALIGN;
318 DBG(DBG_KLIPS, DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: "
319 "sadb_msg_len=%d sadb_supported_len=%d",
320 satype==SADB_SATYPE_ESP? "ESP" : "AH",
321 msg_buf->sadb_msg_len,
327 for (supp_len-=sizeof(struct sadb_supported);
329 supp_len-=sizeof(struct sadb_alg), sadb.alg++,i++) {
331 ret=kernel_alg_add(satype, supp_exttype, sadb.alg);
332 DBG(DBG_KLIPS, DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: "
333 "alg[%d], exttype=%d, satype=%d, alg_id=%d, "
334 "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
336 satype==SADB_SATYPE_ESP? "ESP" : "AH",
340 sadb.alg->sadb_alg_id,
341 sadb.alg->sadb_alg_ivlen,
342 sadb.alg->sadb_alg_minbits,
343 sadb.alg->sadb_alg_maxbits,
344 sadb.alg->sadb_alg_reserved,
351 kernel_alg_esp_enc_keylen(int alg_id)
354 if (!ESP_EALG_PRESENT(alg_id))
356 keylen=esp_ealg[alg_id].sadb_alg_maxbits/BITS_PER_BYTE;
358 DBG(DBG_KLIPS, DBG_log("kernel_alg_esp_enc_keylen():"
359 "alg_id=%d, keylen=%d",
365 kernel_alg_esp_sadb_alg(int alg_id)
367 struct sadb_alg *sadb_alg=NULL;
368 if (!ESP_EALG_PRESENT(alg_id))
370 sadb_alg=&esp_ealg[alg_id];
372 DBG(DBG_KLIPS, DBG_log("kernel_alg_esp_sadb_alg():"
373 "alg_id=%d, sadb_alg=%p",
379 void kernel_alg_show_status(void)
382 struct sadb_alg *alg_p;
383 ESP_EALG_FOR_EACH(sadb_id) {
385 alg_p=&esp_ealg[sadb_id];
386 whack_log(RC_COMMENT, "algorithm ESP encrypt: id=%d, name=%s, "
387 "ivlen=%d, keysizemin=%d, keysizemax=%d"
389 , enum_name(&esp_transformid_names, id)
390 , alg_p->sadb_alg_ivlen
391 , alg_p->sadb_alg_minbits
392 , alg_p->sadb_alg_maxbits
396 ESP_AALG_FOR_EACH(sadb_id) {
397 id=alg_info_esp_sadb2aa(sadb_id);
398 alg_p=&esp_aalg[sadb_id];
399 whack_log(RC_COMMENT, "algorithm ESP auth attr: id=%d, name=%s, "
400 "keysizemin=%d, keysizemax=%d"
402 , enum_name(&auth_alg_names, id)
403 , alg_p->sadb_alg_minbits
404 , alg_p->sadb_alg_maxbits
409 kernel_alg_show_connection(struct connection *c, const char *instance)
413 if (c->alg_info_esp) {
414 alg_info_snprint(buf, sizeof(buf), (struct alg_info *)c->alg_info_esp);
416 , "\"%s\"%s: ESP algorithms wanted: %s"
421 if (c->alg_info_esp) {
422 alg_info_snprint_esp(buf, sizeof(buf), c->alg_info_esp);
424 , "\"%s\"%s: ESP algorithms loaded: %s"
429 st = state_with_serialno(c->newest_ipsec_sa);
430 if (st && st->st_esp.present)
432 , "\"%s\"%s: ESP algorithm newest: %s_%d-%s; pfsgroup=%s"
435 , enum_show(&esp_transformid_names, st->st_esp.attrs.transid)
436 +4 /* strlen("ESP_") */
437 , st->st_esp.attrs.key_len
438 , enum_show(&auth_alg_names, st->st_esp.attrs.auth)+
439 +15 /* strlen("AUTH_ALGORITHM_") */
440 , c->policy & POLICY_PFS ?
441 c->alg_info_esp->esp_pfsgroup ?
442 enum_show(&oakley_group_names,
443 c->alg_info_esp->esp_pfsgroup)
444 +13 /*strlen("OAKLEY_GROUP_")*/
449 #endif /* NO_PLUTO */
452 kernel_alg_esp_auth_ok(int auth, struct alg_info_esp *alg_info)
454 int ret=(ESP_AALG_PRESENT(alg_info_esp_aa2sadb(auth)));
455 if (ret && alg_info &&
456 (alg_info->alg_info_flags & ALG_INFO_F_STRICT)) {
458 struct esp_info *esp_info;
459 ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) {
460 if (esp_info->esp_aalg_id == auth)
465 DBG(DBG_CONTROL | DBG_CRYPT | DBG_PARSING
466 , DBG_log("%s(auth=%d): ret=%d",
467 __FUNCTION__, auth, ret));
473 kernel_alg_esp_auth_keylen(int auth)
475 int sadb_aalg=alg_info_esp_aa2sadb(auth);
478 a_keylen=esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE;
480 DBG(DBG_CONTROL | DBG_CRYPT | DBG_PARSING
481 , DBG_log("%s(auth=%d, sadb_aalg=%d): "
482 "a_keylen=%d", __FUNCTION__, auth, sadb_aalg, a_keylen));
487 kernel_alg_esp_info(int transid, int auth)
489 int sadb_aalg, sadb_ealg;
490 static struct esp_info ei_buf;
492 sadb_aalg=alg_info_esp_aa2sadb(auth);
494 if (!ESP_EALG_PRESENT(sadb_ealg))
496 if (!ESP_AALG_PRESENT(sadb_aalg))
498 memset(&ei_buf, 0, sizeof (ei_buf));
499 ei_buf.transid=transid;
501 ei_buf.enckeylen=esp_ealg[sadb_ealg].sadb_alg_maxbits/BITS_PER_BYTE;
503 ei_buf.authkeylen=esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE;
504 ei_buf.encryptalg=sadb_ealg;
505 ei_buf.authalg=sadb_aalg;
506 DBG(DBG_PARSING, DBG_log("kernel_alg_esp_info():"
507 "transid=%d, auth=%d, ei=%p, "
508 "enckeylen=%d, authkeylen=%d, encryptalg=%d, authalg=%d",
509 transid, auth, &ei_buf,
510 ei_buf.enckeylen, ei_buf.authkeylen,
511 ei_buf.encryptalg, ei_buf.authalg
515 DBG(DBG_PARSING, DBG_log("kernel_alg_esp_info():"
516 "transid=%d, auth=%d, ei=NULL",
523 kernel_alg_policy_algorithms(struct esp_info *esp_info)
525 int ealg_i=esp_info->esp_ealg_id;
534 if (!esp_info->esp_ealg_keylen) {
536 * algos that need KEY_LENGTH
538 * Note: this is a very dirty hack ;-)
541 * Idea: Add a key_length_needed attribute to
544 esp_info->esp_ealg_keylen=
545 esp_ealg[ealg_i].sadb_alg_maxbits;
550 kernel_alg_db_add(struct db_context *db_ctx, struct esp_info *esp_info, lset_t policy)
553 ealg_i=esp_info->esp_ealg_id;
554 if (!ESP_EALG_PRESENT(ealg_i)) {
556 "kernel enc ealg_id=%d not present",
557 __FUNCTION__, ealg_i);
560 if (!(policy & POLICY_AUTHENTICATE)) { /* skip ESP auth attrs for AH */
561 aalg_i=alg_info_esp_aa2sadb(esp_info->esp_aalg_id);
562 if (!ESP_AALG_PRESENT(aalg_i)) {
563 DBG_log("%s() kernel auth "
564 "aalg_id=%d not present",
565 __FUNCTION__, aalg_i);
570 kernel_alg_policy_algorithms(esp_info);
572 /* open new transformation */
573 db_trans_add(db_ctx, ealg_i);
574 /* add ESP auth attr */
575 if (!(policy & POLICY_AUTHENTICATE))
576 db_attr_add_values(db_ctx,
577 AUTH_ALGORITHM, esp_info->esp_aalg_id);
578 /* add keylegth if specified in esp= string */
579 if (esp_info->esp_ealg_keylen) {
580 db_attr_add_values(db_ctx,
581 KEY_LENGTH, esp_info->esp_ealg_keylen);
586 * Create proposal with runtime kernel algos, merging
587 * with passed proposal if not NULL
589 * for now this function does free() previous returned
590 * malloced pointer (this quirk allows easier spdb.c change)
593 kernel_alg_db_new(struct alg_info_esp *alg_info, lset_t policy )
595 int ealg_i, aalg_i, tn=0;
597 const struct esp_info *esp_info;
598 struct esp_info tmp_esp_info;
599 struct db_context *ctx_new=NULL;
601 struct db_prop *prop;
604 if (!(policy & POLICY_ENCRYPT)) { /* not possible, I think */
607 trans_cnt=(esp_ealg_num*esp_aalg_num);
608 DBG(DBG_EMITTING, DBG_log("kernel_alg_db_prop_new() "
609 "initial trans_cnt=%d",
611 /* pass aprox. number of transforms and attributes */
612 ctx_new = db_prop_new(PROTO_IPSEC_ESP, trans_cnt, trans_cnt * 2);
615 * Loop: for each element (struct esp_info) of
616 * alg_info, if kernel support is present then
617 * build the transform (and attrs)
619 * if NULL alg_info, propose everything ...
622 /* passert(alg_info!=0); */
624 ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) {
625 tmp_esp_info = *esp_info;
626 kernel_alg_db_add(ctx_new, &tmp_esp_info, policy);
629 ESP_EALG_FOR_EACH_UPDOWN(ealg_i) {
630 tmp_esp_info.esp_ealg_id=ealg_i;
631 tmp_esp_info.esp_ealg_keylen=0;
632 ESP_AALG_FOR_EACH(aalg_i) {
633 tmp_esp_info.esp_aalg_id=alg_info_esp_sadb2aa(aalg_i);
634 tmp_esp_info.esp_aalg_keylen=0;
635 kernel_alg_db_add(ctx_new, &tmp_esp_info, policy);
640 prop=db_prop_get(ctx_new);
642 DBG(DBG_CONTROL|DBG_EMITTING, DBG_log("kernel_alg_db_prop_new() "
643 "will return p_new->protoid=%d, p_new->trans_cnt=%d",
644 prop->protoid, prop->trans_cnt));
645 for(t=prop->trans,tn=0; tn<prop->trans_cnt; tn++) {
646 DBG(DBG_CONTROL|DBG_EMITTING, DBG_log("kernel_alg_db_prop_new() "
647 " trans[%d]: transid=%d, attr_cnt=%d, "
648 "attrs[0].type=%d, attrs[0].val=%d",
650 t[tn].transid, t[tn].attr_cnt,
651 t[tn].attrs[0].type, t[tn].attrs[0].val
656 #endif /* NO_PLUTO */