diff --git a/include/pcp/key.h b/include/pcp/key.h index ffafe6b..ec0f83b 100644 --- a/include/pcp/key.h +++ b/include/pcp/key.h @@ -108,8 +108,10 @@ struct _pcp_pubkey_t { /* keys.mp+keys.cp+keys.sp+keys.name */ struct _pbp_pubkey_t { byte sigpub[crypto_sign_PUBLICKEYBYTES]; - byte pub[crypto_box_PUBLICKEYBYTES]; byte edpub[crypto_sign_PUBLICKEYBYTES]; + byte pub[crypto_box_PUBLICKEYBYTES]; + char iso_ctime[32]; + char iso_expire[32]; char name[1024]; }; diff --git a/libpcp/base85.c b/libpcp/base85.c index 6f74f98..e8e32e9 100644 --- a/libpcp/base85.c +++ b/libpcp/base85.c @@ -36,7 +36,7 @@ static void prep_base85(void) int decode_85(char *dst, const char *buffer, int len) { prep_base85(); - + int pos = 0; say1("len: %d\n", len); say2("decode 85 <%.*s>\n", len / 4 * 5, buffer); while (len) { @@ -47,13 +47,13 @@ int decode_85(char *dst, const char *buffer, int len) ch = *buffer++; de = de85[ch]; if (--de < 0) - return error("invalid base85 alphabet <%c>\n", ch); + return error("invalid base85 alphabet <%02x> de: %d\n", ch, de); acc = acc * 85 + de; } while (--cnt); ch = *buffer++; de = de85[ch]; - if (--de < 0) - return error("invalid base85 alphabet <%c>\n", ch); + if (--de < 0 && ch != '\0') + return error("invalid base85 alphabet <%02x> left\n", ch); /* Detect overflow. */ @@ -63,8 +63,7 @@ int decode_85(char *dst, const char *buffer, int len) acc += de; /* say1(" %08x\n", acc); */ say1("%.5s", buffer-5); - say2("=> %08x (len: %d)\n", acc, len); - + say2(" => %08x (len: %d)\n", acc, len); cnt = (len < 4) ? len : 4; len -= cnt; do { diff --git a/libpcp/util.c b/libpcp/util.c index 75556db..3715143 100644 --- a/libpcp/util.c +++ b/libpcp/util.c @@ -60,9 +60,17 @@ void _xorbuf(unsigned char *iv, unsigned char *buf, size_t xlen) { /* print some binary data to stderr */ void _dump(char *n, unsigned char *d, size_t s) { - fprintf(stderr, "%s (%ld): ", n, s); + int l = strlen(n) + 9; + fprintf(stderr, "%s (%04ld): ", n, s); size_t i; - for (i=0; i 0) { + fprintf(stderr, "\n"); + for(c=0; c -followed by the binary signature described in B without -the offset separator. +followed by the binary encrypted signature described in B +without the offset separator. + +However, not only the hash of the file content will be signed but the +recipient list described in B as well. A +valid recipient is therefore not able to re-encrypt the decrypted +message, append the original signature and send it to other recipients. +The signature would not match since the recipient list differs and +so recipients know that the signature is forged. + +Formal file description of sign+encrypt format: + + +---------------------------------------------------------+ + | Field Size Description | + +-------------+--------+----------------------------------+ + | Type | 1 | Filetype, 5=ASYM, 23=SYM | + +-------------|--------|----------------------------------+ + | Len R | 4 | Number of recipients (*) | + +-------------|--------|----------------------------------+ + | Recipients | R*72 | C(recipient)|C(recipient)... (*) | + +-------------|--------|----------------------------------+ + | Encrypted | ~ | The actual encrypted data | + +-------------|--------|----------------------------------+ + | Signature | ~ | Encrypted signature(*) | + +-------------|--------|----------------------------------+ + +As usual the encrypted signature consists of a nonce and the +actual cipher, which is computed symmetrically (see above) +from the following clear signature. + +Before encryption the signature format is: + + +---------------------------------------------------------+ + | Field Size Description | + +-------------+--------+----------------------------------+ + | Hash | 64 | BLAKE2 hash of content+R (*) | + +-------------|--------|----------------------------------+ + | Signature | 64 | ED25519 signature of BLAKE2 Hash | + +-------------|--------|----------------------------------+ + +where R is: C(recipient)|C(recipient)... (see B). + +Pseudocode: + + N | crypto_secret_box( crypto_sign( crypto_generichash( M + R, SK ) ), N, S) + +where N is the nonce, M the message, R the recipient list, SK is the senders +secret signing key and S the symmetric key. =head2 Z85 ENCODING diff --git a/src/keymgmt.c b/src/keymgmt.c index 91f8dcc..b1fbe11 100644 --- a/src/keymgmt.c +++ b/src/keymgmt.c @@ -376,9 +376,11 @@ int pcp_importsecret (vault_t *vault, FILE *in) { int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) { pcp_pubkey_t *pub = NULL; if(pbpcompat == 1) { + char *date = NULL; char *parts = NULL; int pnum; pbp_pubkey_t *b = ucmalloc(sizeof(pbp_pubkey_t)); + pcp_pubkey_t *tmp = ucmalloc(sizeof(pcp_pubkey_t)); pub = ucmalloc(sizeof(pcp_pubkey_t)); unsigned char *buf = ucmalloc(2048); unsigned char *bin = ucmalloc(2048); @@ -396,7 +398,8 @@ int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) { nlen -= 1; } } - klen = (nlen / 5) * 4; + + klen = nlen /5 * 4; /*((nlen + (5 - (nlen % 5))) / 5) * 4;*/ if(decode_85((char *)bin, (char *)buf, klen) != 0) goto errimp1; @@ -407,6 +410,9 @@ int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) { goto errimp1; } + if(debug) + _dump("sig", bin, nlen); + /* unpad result, if any */ for(i=klen; i>0; --i) { if(bin[i] != '\0' && i < klen) { @@ -418,6 +424,19 @@ int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) { /* use first part as sig and verify */ memcpy(b, &bin[crypto_sign_BYTES], klen - crypto_sign_BYTES); + if(debug) + _dump("sig", bin, klen); + + /* parse the date */ + date = ucmalloc(19); + memcpy(date, b->iso_ctime, 18); + date[19] = '\0'; + struct tm c; + if(strptime(date, "%Y-%m-%dT%H:%M:%S", &c) == NULL) { + fatal("Failed to parse creation time in PBP public key file (<%s>)\n", date); + goto errimp2; + } + /* parse the name */ parts = strtok (b->name, "<>"); pnum = 0; @@ -433,22 +452,35 @@ int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) { if(strlen(b->name) == 0) { char *owner = pcp_getstdin("Enter the name of the key owner"); - memcpy(b->name, owner, strlen(owner) + 1); + memcpy(pub->owner, owner, strlen(owner) + 1); free(owner); } /* fill in the fields */ - pub->ctime = (long)time(0); /* pbp exports no ctime */ + pub->ctime = (long)mktime(&c); pub->type = PCP_KEY_TYPE_PUBLIC; pub->version = PCP_KEY_VERSION; pub->serial = arc4random(); - memcpy(pub->id, pcp_getpubkeyid(pub), 17); memcpy(pub->pub, b->pub, crypto_box_PUBLICKEYBYTES); memcpy(pub->edpub, b->edpub, crypto_sign_PUBLICKEYBYTES); + memcpy(pub->id, pcp_getpubkeyid(pub), 17); + + /* edpub used for signing, might differ */ + memcpy(tmp->edpub, b->sigpub, crypto_sign_PUBLICKEYBYTES); + + if(debug) { + _dump(" mp", tmp->edpub, crypto_sign_PUBLICKEYBYTES); + _dump(" cp", pub->pub, crypto_sign_PUBLICKEYBYTES); + _dump(" sp", pub->edpub, crypto_sign_PUBLICKEYBYTES); + _dump("name", (unsigned char *)pub->owner, strlen(pub->owner)); + _dump(" sig", bin, klen); + fprintf(stderr, "<%s>\n", (unsigned char *)pub->owner); + pcp_dumppubkey(pub); + } + + unsigned char *sig = pcp_ed_verify(bin, klen, tmp); + free(tmp); - fprintf(stderr, "edpub: "); pcpprint_bin(stderr, pub->edpub, crypto_sign_PUBLICKEYBYTES); fprintf(stderr, "\n"); - fprintf(stderr, " sig: "); pcpprint_bin(stderr, bin, klen); fprintf(stderr, "\n"); - unsigned char *sig = pcp_ed_verify(bin, klen, pub); if(sig == NULL) goto errimp1; @@ -458,6 +490,8 @@ int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) { free(bin); goto kimp; + errimp2: + free(date); errimp1: free(bin); diff --git a/src/keyprint.c b/src/keyprint.c index c6d316e..a5c976f 100644 --- a/src/keyprint.c +++ b/src/keyprint.c @@ -233,23 +233,52 @@ void pcppubkey_print(pcp_pubkey_t *key, FILE* out, int pbpcompat) { secret = pcpkey_decrypt(secret, passphrase); if(secret != NULL) { - size_t pbplen = crypto_sign_PUBLICKEYBYTES+crypto_box_PUBLICKEYBYTES+crypto_sign_PUBLICKEYBYTES+strlen(key->owner); + size_t pbplen = crypto_sign_PUBLICKEYBYTES+crypto_box_PUBLICKEYBYTES+crypto_sign_PUBLICKEYBYTES+strlen(key->owner)+64; + + /* we need to do the padding here, since pbp verifies the sig including the pad */ + /* + int pad = pbplen % 4; + if(pad > 0) { + pad = 4 - pad; + pbplen += pad; + } + */ unsigned char *blob = ucmalloc(pbplen); - fprintf(stderr, "edpub: "); pcpprint_bin(stderr, key->edpub, crypto_sign_PUBLICKEYBYTES); fprintf(stderr, "\n"); - fprintf(stderr, " pub: "); pcpprint_bin(stderr, key->pub, crypto_box_PUBLICKEYBYTES); fprintf(stderr, "\n"); - fprintf(stderr, "edpub: "); pcpprint_bin(stderr, key->edpub, crypto_sign_PUBLICKEYBYTES); fprintf(stderr, "\n"); + if(debug) { + _dump(" mp", secret->edpub, crypto_sign_PUBLICKEYBYTES); + _dump(" cp", key->pub, crypto_sign_PUBLICKEYBYTES); + _dump(" sp", key->edpub, crypto_sign_PUBLICKEYBYTES); + _dump("name", (unsigned char *)key->owner, strlen(key->owner)); + } - memcpy(blob, key->edpub, crypto_sign_PUBLICKEYBYTES); - memcpy(&blob[crypto_sign_PUBLICKEYBYTES], key->pub, crypto_box_PUBLICKEYBYTES); - memcpy(&blob[crypto_sign_PUBLICKEYBYTES+crypto_box_PUBLICKEYBYTES], key->edpub, crypto_sign_PUBLICKEYBYTES); - memcpy(&blob[crypto_sign_PUBLICKEYBYTES+crypto_box_PUBLICKEYBYTES+crypto_sign_PUBLICKEYBYTES], - key->owner, strlen(key->owner)); + /* pkt = keys.sign(keys.mp+keys.sp+keys.cp+dates+keys.name, master=True) */ + memcpy(blob, secret->edpub, crypto_sign_PUBLICKEYBYTES); + memcpy(&blob[crypto_sign_PUBLICKEYBYTES], key->edpub, crypto_sign_PUBLICKEYBYTES); + memcpy(&blob[crypto_sign_PUBLICKEYBYTES*2], key->pub, crypto_box_PUBLICKEYBYTES); + + struct tm *v; + time_t vt = t + 31536000; + v = localtime(&vt); + + char *date = ucmalloc(65); + + sprintf(date, "%04d-%02d-%02dT%02d:%02d:%02d.000000 %04d-%02d-%02dT%02d:%02d:%02d.000000 ", + c->tm_year+1900-1, c->tm_mon+1, c->tm_mday, // wtf? why -1? + c->tm_hour, c->tm_min, c->tm_sec, + v->tm_year+1900-1, v->tm_mon+1, v->tm_mday, + v->tm_hour, v->tm_min, v->tm_sec); + + memcpy(&blob[crypto_sign_PUBLICKEYBYTES+crypto_box_PUBLICKEYBYTES*2], date, 64); + + memcpy(&blob[crypto_sign_PUBLICKEYBYTES+crypto_box_PUBLICKEYBYTES*2+64], key->owner, strlen(key->owner)); unsigned char *sig = pcp_ed_sign(blob, pbplen, secret); - fprintf(stderr, " sig: "); pcpprint_bin(stderr, sig, pbplen+crypto_sign_BYTES); fprintf(stderr, "\n"); - fprintf(stderr, "siglen: %d, inlen: %ld\n", crypto_sign_BYTES, pbplen); + + if(debug) + _dump(" sig", sig, crypto_sign_BYTES+pbplen); + if(sig != NULL) { size_t siglen = pbplen + crypto_sign_BYTES; size_t blen = ((siglen / 4) * 5) + siglen;