1 #include "dat.h" 2 #include "fns.h" 3 #include "error.h" 4 #include "interp.h" 5 #include <isa.h> 6 #include "runt.h" 7 #include "mp.h" 8 #include "libsec.h" 9 #include "../../libkeyring/keys.h" 10 11 /* 12 * experimental version of signed modules 13 */ 14 15 enum 16 { 17 Qdir, 18 Qkey, 19 Qctl, 20 21 Maxkey = 2048 22 }; 23 24 static Dirtab signdir[] = 25 { 26 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, 27 "signerkey", {Qkey}, 0, 0644, 28 "signerctl", {Qctl}, 0, 0600, 29 }; 30 31 typedef struct Get Get; 32 struct Get { 33 uchar* p; 34 uchar* ep; 35 }; 36 37 #define G32(b) ((b[0]<<24)|(b[1]<<16)|(b[2]<<8)|b[3]) 38 39 static int vc(Get*); 40 static int vs(void*, int, Get*, int); 41 static Signerkey* findsignerkey(Skeyset*, char*, int, char*); 42 extern vlong osusectime(void); 43 44 int 45 verifysigner(uchar *sign, int len, uchar *data, ulong ndata) 46 { 47 Get sig; 48 int alg; 49 ulong issued, expires, now; 50 int footprint, r, n; 51 uchar buf[128], digest[SHA1dlen]; 52 DigestState *ds; 53 volatile struct {mpint* b;} b; 54 volatile struct {mpint* s;} s; 55 SigAlgVec *sa; 56 Signerkey *key; 57 Skeyset *sigs; 58 59 /* alg[1] issued[4] expires[4] footprint[2] signer[n] sig[m] */ 60 sigs = up->env->sigs; 61 if(sigs == nil) 62 return 1; /* not enforcing signed modules */ 63 sig.p = sign; 64 sig.ep = sign+len; 65 alg = vc(&sig); 66 if(alg != 2) 67 return 0; /* we do only SHA1/RSA */ 68 sa = findsigalg("rsa"); 69 if(sa == nil) 70 return 0; 71 if(vs(buf, sizeof(buf), &sig, 4) < 0) 72 return 0; 73 now = osusectime()/1000000; 74 issued = G32(buf); 75 if(vs(buf, sizeof(buf), &sig, 4) < 0) 76 return 0; 77 if(issued != 0 && now < issued) 78 return 0; 79 expires = G32(buf); 80 if(expires != 0 && now >= expires) 81 return 0; 82 footprint = vc(&sig) << 8; 83 footprint |= vc(&sig); 84 if(footprint < 0) 85 return 0; 86 r = 0; 87 b.b = nil; 88 s.s = nil; 89 qlock(&sigs->l); 90 if(waserror()) 91 goto out; 92 if((n = vs(buf, sizeof(buf)-NUMSIZE-1, &sig, -1)) < 0) /* owner */ 93 goto out; 94 buf[n] = 0; 95 key = findsignerkey(sigs, sa->name, footprint, (char*)buf); 96 if(key == nil) 97 goto out; 98 n += snprint((char*)buf+n, NUMSIZE, " %lud", expires); 99 ds = sha1(buf, n, nil, nil); 100 sha1(data, ndata, digest, ds); 101 b.b = betomp(digest, SHA1dlen, nil); 102 if(b.b == nil) 103 goto out; 104 s.s = betomp(sig.p, sig.ep-sig.p, nil); 105 if(s.s == nil) 106 goto out; 107 r = (*sa->verify)(b.b, s.s, key->pk); 108 out: 109 qunlock(&sigs->l); 110 if(b.b != nil) 111 mpfree(b.b); 112 if(s.s != nil) 113 mpfree(s.s); 114 return r; 115 } 116 117 int 118 mustbesigned(char *path, uchar *code, ulong length, Dir *dir) 119 { 120 USED(code); USED(length); 121 if(0)print("load %s: %d %C\n", path, up->env->sigs!=nil, dir==nil?'?':dir->type); 122 /* allow only signed modules and those in #/; already loaded modules are reloaded from cache */ 123 return up->env->sigs != nil && (dir == nil || dir->type != '/'); 124 } 125 126 static int 127 vc(Get *g) 128 { 129 return g->p < g->ep? *g->p++: -1; 130 } 131 132 static int 133 vs(void *s, int lim, Get *g, int n) 134 { 135 int nr; 136 137 if(n < 0){ 138 if(g->p >= g->ep) 139 return -1; 140 n = *g->p++; 141 lim--; 142 } 143 if(n > lim) 144 return -1; 145 nr = g->ep - g->p; 146 if(n > nr) 147 return -1; 148 if(s != nil) 149 memmove(s, g->p, n); 150 g->p += n; 151 return n; 152 } 153 154 static char* 155 cstring(char *str, char **strp) 156 { 157 char *p, *s; 158 int n; 159 160 p = strchr(str, '\n'); 161 if(p == 0) 162 p = str + strlen(str); 163 n = p - str; 164 s = malloc(n+1); 165 if(s == nil) 166 return nil; 167 memmove(s, str, n); 168 s[n] = 0; 169 170 if(strp){ 171 if(*p) 172 p++; 173 *strp = p; 174 } 175 176 return s; 177 } 178 179 static SigAlgVec* 180 cstrtoalg(char *str, char **strp) 181 { 182 int n; 183 char *p, name[KNAMELEN]; 184 185 p = strchr(str, '\n'); 186 if(p == 0){ 187 p = str + strlen(str); 188 if(strp) 189 *strp = p; 190 } else { 191 if(strp) 192 *strp = p+1; 193 } 194 195 n = p - str; 196 if(n >= sizeof(name)) 197 return nil; 198 strncpy(name, str, n); 199 name[n] = 0; 200 return findsigalg(name); 201 } 202 203 static Signerkey* 204 strtopk(char *buf) 205 { 206 SigAlgVec *sa; 207 char *p; 208 Signerkey *key; 209 210 key = malloc(sizeof(*key)); 211 if(key == nil) 212 return nil; 213 key->r.ref = 1; 214 sa = cstrtoalg(buf, &p); 215 if(sa == nil){ 216 free(key); 217 return nil; 218 } 219 key->alg = sa; 220 key->pkfree = sa->pkfree; 221 key->owner = cstring(p, &p); 222 if(key->owner == nil){ 223 free(key); 224 return nil; 225 } 226 key->pk = (*sa->str2pk)(p, &p); 227 if(key->pk == nil){ 228 free(key->owner); 229 free(key); 230 return nil; 231 } 232 return key; 233 } 234 235 static Signerkey* 236 findsignerkey(Skeyset *sigs, char *alg, int footprint, char *owner) 237 { 238 int i; 239 Signerkey *key; 240 241 for(i=0; i<sigs->nkey; i++){ 242 key = sigs->keys[i]; 243 if(key->footprint == footprint && 244 strcmp(alg, ((SigAlgVec*)key->alg)->name) == 0 && 245 strcmp(key->owner, owner) == 0) 246 return key; 247 } 248 return nil; 249 } 250 251 static Chan* 252 signattach(char *spec) 253 { 254 return devattach(0x03A3, spec); /* L'Σ' */ 255 } 256 257 static Walkqid* 258 signwalk(Chan *c, Chan *nc, char **name, int nname) 259 { 260 return devwalk(c, nc, name, nname, signdir, nelem(signdir), devgen); 261 } 262 263 static int 264 signstat(Chan *c, uchar *db, int n) 265 { 266 return devstat(c, db, n, signdir, nelem(signdir), devgen); 267 } 268 269 static Chan* 270 signopen(Chan *c, int omode) 271 { 272 if(c->qid.type & QTDIR) { 273 if(omode != OREAD) 274 error(Eisdir); 275 c->mode = openmode(omode); 276 c->flag |= COPEN; 277 c->offset = 0; 278 return c; 279 } 280 281 switch((ulong)c->qid.path){ 282 case Qctl: 283 if(!iseve()) 284 error(Eperm); 285 break; 286 287 case Qkey: 288 if(omode != OREAD && !iseve()) 289 error(Eperm); 290 break; 291 } 292 293 c->mode = openmode(omode); 294 c->flag |= COPEN; 295 c->offset = 0; 296 return c; 297 } 298 299 static void 300 signclose(Chan *c) 301 { 302 USED(c); 303 } 304 305 static long 306 signread(Chan *c, void *va, long n, vlong offset) 307 { 308 char *buf, *p; 309 SigAlgVec *sa; 310 Skeyset *sigs; 311 Signerkey *key; 312 int i; 313 314 if(c->qid.type & QTDIR) 315 return devdirread(c, va, n, signdir, nelem(signdir), devgen); 316 sigs = up->env->sigs; 317 if(sigs == nil) 318 return 0; 319 switch((ulong)c->qid.path){ 320 case Qkey: 321 buf = smalloc(Maxkey); 322 if(waserror()){ 323 free(buf); 324 nexterror(); 325 } 326 qlock(&sigs->l); 327 if(waserror()){ 328 qunlock(&sigs->l); 329 nexterror(); 330 } 331 p = buf; 332 for(i=0; i<sigs->nkey; i++){ 333 key = sigs->keys[i]; 334 sa = key->alg; 335 p = seprint(p, buf+Maxkey, "owner=%s alg=%s footprint=%ud expires=%lud\n", 336 key->owner, sa->name, key->footprint, key->expires); 337 } 338 poperror(); 339 qunlock(&sigs->l); 340 n = readstr(offset, va, n, buf); 341 poperror(); 342 free(buf); 343 return n; 344 345 case Qctl: 346 return readnum(offset, va, n, sigs->nkey, NUMSIZE); 347 } 348 return 0; 349 } 350 351 static long 352 signwrite(Chan *c, void *va, long n, vlong offset) 353 { 354 char *buf; 355 Skeyset *sigs; 356 Signerkey *okey, *key; 357 int i; 358 359 if(c->qid.type & QTDIR) 360 error(Eisdir); 361 USED(offset); 362 switch((ulong)c->qid.path){ 363 case Qkey: 364 if(n >= Maxkey) 365 error(Etoobig); 366 buf = smalloc(Maxkey); 367 if(waserror()){ 368 free(buf); 369 nexterror(); 370 } 371 memmove(buf, va, n); 372 buf[n] = 0; 373 374 key = strtopk(buf); 375 if(key == nil) 376 error("bad key syntax"); 377 poperror(); 378 free(buf); 379 380 if(waserror()){ 381 freeskey(key); 382 nexterror(); 383 } 384 sigs = up->env->sigs; 385 if(sigs == nil){ 386 sigs = malloc(sizeof(*sigs)); 387 if(sigs == nil) 388 error(Enomem); 389 sigs->r.ref = 1; 390 up->env->sigs = sigs; 391 } 392 qlock(&sigs->l); 393 if(waserror()){ 394 qunlock(&sigs->l); 395 nexterror(); 396 } 397 for(i=0; i<sigs->nkey; i++){ 398 okey = sigs->keys[i]; 399 if(strcmp(okey->owner, key->owner) == 0){ 400 /* replace existing key */ 401 sigs->keys[i] = key; 402 freeskey(okey); 403 break; 404 } 405 } 406 if(i >= sigs->nkey){ 407 if(sigs->nkey >= nelem(sigs->keys)) 408 error("too many keys"); 409 sigs->keys[sigs->nkey++] = key; 410 } 411 poperror(); 412 qunlock(&sigs->l); 413 poperror(); /* key */ 414 415 return n; 416 case Qctl: 417 error(Ebadctl); 418 break; 419 } 420 return 0; 421 } 422 423 Dev signdevtab = { 424 0x03A3, /* L'Σ', /* U+03A3 */ 425 "sign", 426 427 devinit, 428 signattach, 429 signwalk, 430 signstat, 431 signopen, 432 devcreate, 433 signclose, 434 signread, 435 devbread, 436 signwrite, 437 devbwrite, 438 devremove, 439 devwstat 440 }; 441