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