From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 25946 invoked from network); 24 Jun 2022 00:11:29 -0000 Received: from 9front.inri.net (168.235.81.73) by inbox.vuxu.org with ESMTPUTF8; 24 Jun 2022 00:11:29 -0000 Received: from mimir.eigenstate.org ([206.124.132.107]) by 9front; Thu Jun 23 20:08:41 -0400 2022 Received: from abbatoir.myfiosgateway.com (pool-74-108-56-225.nycmny.fios.verizon.net [74.108.56.225]) by mimir.eigenstate.org (OpenSMTPD) with ESMTPSA id c52ec9dc (TLSv1.2:ECDHE-RSA-AES256-SHA:256:NO) for <9front@9front.org>; Thu, 23 Jun 2022 17:08:35 -0700 (PDT) Message-ID: To: 9front@9front.org Date: Thu, 23 Jun 2022 20:08:34 -0400 From: ori@eigenstate.org MIME-Version: 1.0 Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: social browser-oriented blockchain JSON standard rails scripting-scale metadata Subject: [9front] upas/dkim: dkim signing for upas Reply-To: 9front@9front.org Precedence: bulk This change adds support for dkim signing to upas. It has2 pieces: 1. Adding support for different asn1 formats to auth/rsa2asn1; we can now generate SubjectPublicKeyInfo RSA keys, which wrap the keys up with an algorithm identifier. 2. Adding a upas/dkim command which filters a message and signs it using dkim. To configure dkim, you need to generate a (small-ish) rsa key; large keys do not fit into DNS text records: # generate the private key and add it to factotum ramfs -p cd /tmp auth/rsagen -b 2048 -t 'service=dkim role=sign hash=sha256 domain=orib.dev owner=*' > dkim.key cat dkim.key > factotum.ctl # extract the public key, encode it, and strip out the junk pubkey=`{ 1) usage(); + n = -1; if((k = getrsakey(argc, argv, privatekey, nil)) == nil) sysfatal("%r"); if(privatekey){ - if((n = asn1encodeRSApriv(k, buf, sizeof(buf))) < 0) - sysfatal("asn1encodeRSApriv: %r"); + if(strcmp(format, "pkcs1") == 0) + n = asn1encodeRSApriv(k, buf, sizeof(buf)); + else + sysfatal("unknown format %s", format); + if(n < 0) + sysfatal("encode: %r"); }else{ - if((n = asn1encodeRSApub(&k->pub, buf, sizeof(buf))) < 0) - sysfatal("asn1encodeRSApub: %r"); + if(strcmp(format, "pkcs1") == 0) + n = asn1encodeRSApub(&k->pub, buf, sizeof(buf)); + else if(strcmp(format, "spki") == 0) + n = asn1encodeRSApubSPKI(&k->pub, buf, sizeof(buf)); + else + sysfatal("unknown format %s", format); + if(n < 0) + sysfatal("encode: %r"); } if(write(1, buf, n) != n) sysfatal("write: %r"); --- /dev/null +++ b//sys/src/cmd/upas/dkim/dkim.c @@ -1,0 +1,210 @@ +#include +#include +#include +#include +#include +#include +#include + +char *signhdr[] = { + "from:", + "to:", + "subject:", + "date:", + "message-id:", + nil +}; + +char *keyspec; +char *domain; +char *selector = "dkim"; + +int +trim(char *p) +{ + char *e; + + for(e = p; *e != 0; e++) + if(*e == '\r' || *e == '\n') + break; + *e = 0; + return e - p; +} + +int +usehdr(char *ln, char **hs) +{ + char **p; + + for(p = signhdr; *p; p++) + if(cistrncmp(ln, *p, strlen(*p)) == 0){ + if((*hs = realloc(*hs, strlen(*hs) + strlen(*p) + 1)) == nil) + sysfatal("realloc: %r"); + strcat(*hs, *p); + return 1; + } + return 0; +} + +void +append(char **m, int *nm, int *sz, char *ln, int n) +{ + while(*nm + n + 2 >= *sz){ + *sz += *sz/2; + *m = realloc(*m, *sz); + } + memcpy(*m + *nm, ln, n); + memcpy(*m + *nm + n, "\r\n", 2); + *nm += n+2; +} + + +int +sign(uchar *hash, int nhash, char **sig, int *nsig) +{ + AuthRpc *rpc; + int afd; + + if((afd = open("/mnt/factotum/rpc", ORDWR|OCEXEC)) < 0) + return -1; + if((rpc = auth_allocrpc(afd)) == nil){ + close(afd); + return -1; + } + if(auth_rpc(rpc, "start", keyspec, strlen(keyspec)) != ARok){ + auth_freerpc(rpc); + close(afd); + return -1; + } + + if(auth_rpc(rpc, "write", hash, nhash) != ARok) + sysfatal("sign: write hash: %r"); + if(auth_rpc(rpc, "read", nil, 0) != ARok) + sysfatal("sign: read sig: %r"); + if((*sig = malloc(rpc->narg)) == nil) + sysfatal("malloc: %r"); + *nsig = rpc->narg; + memcpy(*sig, rpc->arg, *nsig); + auth_freerpc(rpc); + close(afd); + return 0; +} + +void +usage(void) +{ + fprint(2, "usage: %s [-s sel] -d dom\n", argv0); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + int i, n, nhdr, nmsg, nsig, ntail, hdrsz, msgsz, use; + uchar hdrhash[SHA2_256dlen], msghash[SHA2_256dlen]; + char *hdr, *msg, *sig, *ln, *hdrset, *dhdr; + Biobuf *rd, *wr; + DigestState *sh, *sb; + + ARGBEGIN{ + case 'd': + domain = EARGF(usage()); + break; + case 's': + selector = EARGF(usage()); + break; + default: + usage(); + break; + }ARGEND; + + if(domain == nil) + usage(); + fmtinstall('H', encodefmt); + fmtinstall('[', encodefmt); + keyspec = smprint("proto=rsa service=dkim role=sign hash=sha256 domain=%s", domain); + + rd = Bfdopen(0, OREAD); + wr = Bfdopen(1, OWRITE); + + nhdr = 0; + hdrsz = 32; + if((hdr = malloc(hdrsz)) == nil) + sysfatal("malloc: %r"); + nmsg = 0; + msgsz = 32; + if((msg = malloc(msgsz)) == nil) + sysfatal("malloc: %r"); + + use = 0; + sh = nil; + hdrset = strdup(""); + while((ln = Brdstr(rd, '\n', 1)) != nil){ + n = trim(ln); + if(n == 0 + || (n == 1 && ln[0] == '\r' || ln[0] == '\n') + || (n == 2 && strcmp(ln, "\r\n") == 0)) + break; + /* + * strip out existing DKIM signatures, + * for the sake of mailing lists and such. + */ + if(cistrcmp(ln, "DKIM-Signature:") == 0) + continue; + if(ln[0] != ' ' && ln[0] != '\t') + use = usehdr(ln, &hdrset); + if(use){ + sh = sha2_256((uchar*)ln, n, nil, sh); + sh = sha2_256((uchar*)"\r\n", 2, nil, sh); + } + append(&hdr, &nhdr, &hdrsz, ln, n); + } + + sb = nil; + ntail = 0; + while((ln = Brdstr(rd, '\n', 0)) != nil){ + n = trim(ln); + if(n == 0){ + ntail++; + continue; + } + for(i = 0; i < ntail; i++){ + sb = sha2_256((uchar*)"\r\n", 2, nil, sb); + append(&msg, &nmsg, &msgsz, "", 0); + ntail = 0; + } + sb = sha2_256((uchar*)ln, n, nil, sb); + sb = sha2_256((uchar*)"\r\n", 2, nil, sb); + append(&msg, &nmsg, &msgsz, ln, n); + } + if(nmsg == 0 || ntail > 1) + sb = sha2_256((uchar*)"\r\n", 2, nil, sb); + Bterm(rd); + + sha2_256(nil, 0, msghash, sb); + dhdr = smprint( + "DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=%s;\r\n" + " h=%s; s=%s;\r\n" + " bh=%.*[; \r\n" + " b=", + domain, hdrset, selector, + (int)sizeof(msghash), msghash); + if(dhdr == nil) + sysfatal("smprint: %r"); + sh = sha2_256((uchar*)dhdr, strlen(dhdr), nil, sh); + sha2_256(nil, 0, hdrhash, sh); + if(sign(hdrhash, sizeof(hdrhash), &sig, &nsig) == -1) + sysfatal("sign: %r"); + + Bwrite(wr, dhdr, strlen(dhdr)); + Bprint(wr, "%.*[\r\n", nsig, sig); + Bwrite(wr, hdr, nhdr); + Bprint(wr, "\n"); + Bwrite(wr, msg, nmsg); + Bterm(wr); + + free(hdr); + free(msg); + free(sig); + exits(nil); +} --- /dev/null +++ b//sys/src/cmd/upas/dkim/mkfile @@ -1,0 +1,7 @@ +data; @@ -2900,6 +2901,32 @@ } memmove(buf, b->data, len = b->len); freebytes(b); + return len; +} + +int +asn1encodeRSApubSPKI(RSApub *pk, uchar *buf, int len) +{ + Bytes *b, *k; + Elem e; + + k = encode_rsapubkey(pk); + if(k == nil) + return -1; + e = mkseq( + mkel(mkalg(ALG_rsaEncryption), + mkel(mkbits(k->data, k->len), + nil))); + encode(e, &b); + freebytes(k); + if(b == nil) + return -1; + if(b->len > len){ + freebytes(b); + werrstr("buffer too small"); + return -1; + } + memmove(buf, b->data, len = b->len); return len; }