4 # secnet - pubkeys.fl.pl
6 # This file is part of secnet.
7 # See README for full list of copyright holders.
9 # secnet is free software; you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
14 # secnet is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 # General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # version 3 along with secnet; if not, see
21 # https://www.gnu.org/licenses/gpl.html.
23 # We process __DATA__ of this file first through the perl code,
24 # and then through flex. We do it like this because directives
25 # with positional arguments are otherwise rather tedious to specify
26 # in flex. Of course we could have used bison too but this seems
39 our %subst = (GRPIDSZ => 4, SERIALSZ => 4);
43 my ($always, $delta) = @_;
46 if ($always || $. != $last_lno+1) {
47 $o .= sprintf "#line %d \"%s\"\n", $delta+$data_off+$., $0;
55 if (m/^!SUBSTCHECKS\s*$/) {
56 foreach (keys %subst) {
59 # error $_ value disagrees between pubkeys.fl.pl and C headers
75 s#\{!2(\w+)\}# '{'.(2 * ($subst{$1}//die "$1 ?")).'}' #ge;
76 if (m/^!(KEYWORD|KWALIAS) ([-0-9a-z]+)(\s*\{.*\})?$/) {
78 if ($1 eq 'KEYWORD') {
86 $kwid = $kw; $kwid =~ y/-/_/;
88 $co .= "{L}$kwt { BEGIN($in_s); $xact }\n";
91 if (m/^!ARG (\w+) (\S.*\S) \{\s*$/) {
94 $co .= inst("$in_s")."{S} { BEGIN(D_${kwid}_$1); }\n";
95 $co .= inst("D_${kwid}_$1")."$2 {\n";
96 $in_s = "HA_${kwid}_$1";
97 $co .= "\tBEGIN($in_s);\n";
106 $kw = shift @next_kw;
109 if (m/^!FINAL \{\s*$/) {
112 $co .= inst("FIN_$kwid")."\\n { BEGIN(0); c->loc.line++; }\n";
113 $co .= inst("$in_s")."{L}/\\n {\n";
114 $co .= "\tBEGIN(FIN_$kwid);\n";
128 print $do, "%%\n", $co or die $!;
130 BEGIN { $data_off = __LINE__ + 1; }
135 BASE91S []-~!#-&(-[]+
144 %option never-interactive
146 %option prefix="pkyy"
155 #include "unaligned.h"
156 #include "base91s/base91.h"
160 struct pubkeyset_context {
161 /* filled in during setup: */
162 struct cloc loc; /* line is runtime */
164 struct hash_if *defhash;
165 struct buffer_if *data_buf;
166 struct peer_keyset *building;
169 bool_t fallback_skip;
170 const struct sigscheme_info *scheme;
171 uint8_t grpid[GRPIDSZ];
175 static struct pubkeyset_context c[1];
178 #define HEX2BIN(v,l) ({ \
180 bool_t ok=hex_decode((v), ((l)), &outlen, yytext, False); \
182 assert(outlen==((l))); \
184 #define HEX2BIN_ARRAY(v) HEX2BIN((v),sizeof((v)))
189 #define DOSKIP(m) ({ \
190 slilog(LI,M_INFO,"%s:%d: " m, c->loc.file, c->loc.line); \
193 #define FAIL(m) do{ \
194 slilog(LI,M_ERR,"%s:%d: " m, c->loc.file, c->loc.line); \
202 !KEYWORD pkg { c->fallback_skip=0; }
203 !KWALIAS pkgf { c->fallback_skip=!!c->building->nkeys; }
204 !ARG id [0-9a-f]{!2GRPIDSZ} {
205 HEX2BIN_ARRAY(c->grpid);
210 !ARG algo [-0-9a-z]+ {
211 if (c->fallback_skip) DOSKIP("fallback not needed");
212 c->scheme = sigscheme_lookup(yytext);
213 if (!c->scheme) DOSKIP("unknown pk algorithm");
215 !ARG data {BASE91S} {
216 /* baseE91 and thus base91s can sometimes store 14 bits per
217 * character pair, so the max decode ratio is 14/16. */
218 size_t maxl = base91s_decode_maxlen(yyleng);
219 buffer_init(c->data_buf,0);
220 if (buf_remaining_space(c->data_buf) < maxl) DOSKIP("pk data too long");
223 size_t l = base91s_decode(&b91, yytext, yyleng, c->data_buf->start);
224 l += base91s_decode_end(&b91, c->data_buf->start + l);
226 buf_append(c->data_buf,l);
229 if (c->building->nkeys >= MAX_SIG_KEYS) DOSKIP("too many public keys");
230 struct sigpubkey_if *pubkey;
232 bool_t ok=c->scheme->loadpub(c->scheme,c->data_buf,
233 &pubkey,&cl,c->log,c->loc);
235 if (pubkey->sethash) {
237 pubkey->dispose(pubkey->st);
238 DOSKIP("public key requires default hash to load");
240 pubkey->sethash(pubkey->st,c->defhash);
242 struct peer_pubkey *fill=&c->building->keys[c->building->nkeys];
243 memcpy(fill->id.b,c->grpid,GRPIDSZ);
244 assert(ALGIDSZ==1); /* otherwise need htons or htonl or something */
245 fill->id.b[GRPIDSZ]=c->scheme->algid;
247 c->building->nkeys++;
251 !ARG id [0-9a-f]{!2SERIALSZ} {
252 if (c->had_serial) FAIL("`serial' repeated");
254 uint8_t sb[SERIALSZ];
256 c->serial=get_uint32(sb);
262 DOSKIP("unknown directive");
277 <INITIAL><<EOF>> { return 0; }
284 slilog(LI,M_DEBUG,"pubkeys syntax error at `%s'", yytext);
285 FAIL("syntax error");
287 <*>\n { FAIL("syntax error - unexpected newline"); }
288 <<EOF>> { FAIL("syntax error - unexpected eof"); }
292 extern struct peer_keyset *
293 keyset_load(const char *path, struct buffer_if *data_buf,
294 struct log_if *log, int logcl_enoent,
295 struct hash_if *defhash) {
296 assert(!c->building);
300 pkyyin = fopen(path, "r");
303 errno==ENOENT ? logcl_enoent : M_ERR,
304 "%scould not open keyset file %s: %s",
305 logcl_enoent==M_DEBUG && errno==ENOENT ? "expectedly " : "",
306 path,strerror(errno));
312 c->data_buf=data_buf;
314 c->building->nkeys=0;
315 c->building->refcount=1;
324 if (!c->building->nkeys) {
325 slilog(LI,M_ERR,"no useable keys in %s",path);
329 struct peer_keyset *built=c->building;
336 if (c->building) { free(c->building); c->building=0; }
337 if (pkyyin) { fclose(pkyyin); pkyyin=0; }