From efdf2987aec35d1c4cdbf19d5c54877f19c98b76 Mon Sep 17 00:00:00 2001 From: TLINDEN Date: Mon, 10 Feb 2014 11:37:42 +0100 Subject: [PATCH] moved the actual public key export code out into the lib (mgmt.c). cmdline client does only armor the blobs, if neccessary. Also, armored pubkey exports don't contain any comments anymore. --- include/pcp/mgmt.h | 11 ++- libpcp/mgmt.c | 78 ++++++++++++++--- src/keymgmt.c | 204 ++++++++++++++++++++++----------------------- src/keymgmt.h | 10 ++- src/keyprint.c | 204 ++++++++++++--------------------------------- src/keyprint.h | 2 +- 6 files changed, 234 insertions(+), 275 deletions(-) diff --git a/include/pcp/mgmt.h b/include/pcp/mgmt.h index be2a3b1..a428ea1 100644 --- a/include/pcp/mgmt.h +++ b/include/pcp/mgmt.h @@ -35,6 +35,7 @@ #include "key.h" #include "buffer.h" +/* key management api, export, import, yaml and stuff */ @@ -128,7 +129,15 @@ typedef struct _pcp_rfc_pubkey_sig_0x21_t rfc_pub_sig; #define EXP_PK_FOOTER "------END ED25519-CURVE29915 PUBLICKEY------" +/* pubkey export formats */ +#define EXP_FORMAT_NATIVE 0x01 +#define EXP_FORMAT_PBP 0x03 + + /* export public key */ -Buffer *pcp_get_rfc_pub (pcp_pubkey_t *key, pcp_key_t *sk); +Buffer *pcp_export_rfc_pub (pcp_key_t *sk); + +/* export public key in pbp format */ +Buffer *pcp_export_pbp_pub(pcp_key_t *sk); #endif // _HAVE_PCP_MGMT_H diff --git a/libpcp/mgmt.c b/libpcp/mgmt.c index c5c3ad0..78a65a1 100644 --- a/libpcp/mgmt.c +++ b/libpcp/mgmt.c @@ -22,20 +22,72 @@ #include "mgmt.h" +Buffer *pcp_export_pbp_pub(pcp_key_t *sk) { + struct tm *v, *c; + unsigned char *signature = NULL; + char *date = NULL; -Buffer *pcp_get_rfc_pub (pcp_pubkey_t *key, pcp_key_t *sk) { + Buffer *out = buffer_new(320, "pbp01"); + Buffer *sig = buffer_new(320, "pbsig01"); + + /* add raw key material */ + buffer_add(sig, sk->edpub, crypto_sign_PUBLICKEYBYTES); + buffer_add(sig, sk->edpub, crypto_sign_PUBLICKEYBYTES); + buffer_add(sig, sk->pub, crypto_box_PUBLICKEYBYTES); + + /* add creatioin and expire time as 32byte iso time string */ + time_t t = (time_t)sk->ctime; + c = localtime(&t); + time_t vt = t + 31536000; + v = localtime(&vt); + 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); + buffer_add(sig, date, 64); + + /* add owner */ + buffer_add(sig, sk->owner, strlen(sk->owner)); + + /* calculate the signed key blob */ + signature = pcp_ed_sign(buffer_get(sig), buffer_size(sig), sk); + + if(signature == NULL) + goto exppbperr01; + + /* put it out */ + buffer_add_buf(out, sig); + + free(date); + buffer_free(sig); + free(v); + return out; + + + exppbperr01: + buffer_free(sig); + buffer_free(out); + free(date); + free(v); + return NULL; +} + + +Buffer *pcp_export_rfc_pub (pcp_key_t *sk) { Buffer *out = buffer_new(320, "bo1"); Buffer *raw = buffer_new(256, "bs1"); /* add the header */ buffer_add8(out, PCP_KEY_VERSION); - buffer_add32(out, key->ctime); + buffer_add32(out, sk->ctime); buffer_add8(out, EXP_PK_CIPHER); /* add the keys */ - buffer_add(raw, key->edpub, 32); - buffer_add(raw, key->edpub, 32); - buffer_add(raw, key->pub, 32); + buffer_add(raw, sk->masterpub, 32); + buffer_add(raw, sk->edpub, 32); + buffer_add(raw, sk->pub, 32); /* add the sig header */ buffer_add8(raw, EXP_SIG_VERSION); @@ -57,25 +109,25 @@ Buffer *pcp_get_rfc_pub (pcp_pubkey_t *key, pcp_key_t *sk) { /* add key expire time */ buffer_add32be(raw, 4); buffer_add8(raw, EXP_SIG_SUB_KEYEXPIRE); - buffer_add32be(raw, key->ctime + 31536000); + buffer_add32be(raw, sk->ctime + 31536000); /* add name notation sub*/ - size_t notation_size = strlen(key->owner) + 4 + 5; + size_t notation_size = strlen(sk->owner) + 4 + 5; buffer_add32be(raw, notation_size); buffer_add8(raw, EXP_SIG_SUB_NOTATION); buffer_add16be(raw, 5); - buffer_add16be(raw, strlen(key->owner)); + buffer_add16be(raw, strlen(sk->owner)); buffer_add(raw, "owner", 5); - buffer_add(raw, key->owner, strlen(key->owner)); + buffer_add(raw, sk->owner, strlen(sk->owner)); /* add mail notation sub */ - notation_size = strlen(key->mail) + 4 + 4; + notation_size = strlen(sk->mail) + 4 + 4; buffer_add32be(raw, notation_size); buffer_add8(raw, EXP_SIG_SUB_NOTATION); buffer_add16be(raw, 4); - buffer_add16be(raw, strlen(key->mail)); + buffer_add16be(raw, strlen(sk->mail)); buffer_add(raw, "mail", 4); - buffer_add(raw, key->mail, strlen(key->mail)); + buffer_add(raw, sk->mail, strlen(sk->mail)); /* add key flags */ buffer_add32be(raw, 1); @@ -91,7 +143,7 @@ Buffer *pcp_get_rfc_pub (pcp_pubkey_t *key, pcp_key_t *sk) { crypto_generichash_final(st, hash, crypto_generichash_BYTES_MAX); /* sign the hash */ - unsigned char *sig = pcp_ed_sign(hash, crypto_generichash_BYTES_MAX, sk->secret); + unsigned char *sig = pcp_ed_sign_key(hash, crypto_generichash_BYTES_MAX, sk); /* append the signature packet to the output */ buffer_add(out, buffer_get(raw), buffer_size(raw)); diff --git a/src/keymgmt.c b/src/keymgmt.c index 4fccf77..76399e9 100644 --- a/src/keymgmt.c +++ b/src/keymgmt.c @@ -259,63 +259,118 @@ void pcp_exportsecretkey(pcp_key_t *key, char *outfile) { keyid we use the primary key. if no keyid has been given but a recipient instead, we try to look up the vault for a match. */ -void pcp_exportpublic(char *keyid, char *recipient, char *passwd, char *outfile, int pbpcompat) { - pcp_pubkey_t *key = NULL; - +void pcp_exportpublic(char *keyid, char *passwd, char *outfile, int format, int armor) { + FILE *out; + int is_foreign = 0; + pcp_pubkey_t *pk = NULL; + pcp_key_t *sk = NULL; + Buffer *exported_pk; + + if(outfile == NULL) { + out = stdout; + } + else { + if((out = fopen(outfile, "wb+")) == NULL) { + fatal("Could not create output file %s", outfile); + goto errpcpexpu1; + } + } + + if(keyid != NULL) { - /* look if we've got that one */ - HASH_FIND_STR(pcppubkey_hash, keyid, key); - if(key == NULL) { - /* maybe it's a secret key? */ - pcp_key_t *s = NULL; - HASH_FIND_STR(pcpkey_hash, keyid, s); - if(s == NULL) { - fatal("Could not find a public key with id 0x%s in vault %s!\n", keyid, vault->filename); - free(s); + /* keyid specified, check if it exists and if yes, what type it is */ + HASH_FIND_STR(pcppubkey_hash, keyid, pk); + if(pk == NULL) { + /* ok, so, then look for a secret key with that id */ + HASH_FIND_STR(pcpkey_hash, keyid, sk); + if(sk == NULL) { + fatal("Could not find a key with id 0x%s in vault %s!\n", + keyid, vault->filename); + goto errpcpexpu1; } else { - key = pcpkey_pub_from_secret(s); + /* ok, so it's our own key */ + is_foreign = 0; } } + else { + /* it's a foreign public key, we cannot sign it ourselfes */ + is_foreign = 1; + } } else { - /* look for the primary secret */ - pcp_key_t *s = NULL; - s = pcp_find_primary_secret(); - if(s == NULL) { + /* we use our primary key anyway */ + sk = pcp_find_primary_secret(); + if(sk == NULL) { fatal("There's no primary secret key in the vault %s!\n", vault->filename); - free(s); - } - else { - key = pcpkey_pub_from_secret(s); + goto errpcpexpu1; } + is_foreign = 0; } - if(key != NULL) { - FILE *out; - if(outfile == NULL) { - out = stdout; + + if(is_foreign == 0) { + /* decrypt the secret key */ + char *passphrase; + pcp_readpass(&passphrase, + "Enter passphrase to decrypt your secret key", NULL, 1); + sk = pcpkey_decrypt(sk, passphrase); + if(sk == NULL) { + goto errpcpexpu1; + memset(passphrase, 0, strlen(passphrase)); + free(passphrase); } - else { - if((out = fopen(outfile, "wb+")) == NULL) { - fatal("Could not create output file %s", outfile); - out = NULL; + memset(passphrase, 0, strlen(passphrase)); + free(passphrase); + } + + /* now, we're ready for the actual export */ + if(format == EXP_FORMAT_NATIVE) { + if(is_foreign == 0) { + exported_pk = pcp_export_rfc_pub(sk); + if(exported_pk != NULL) { + if(armor == 1) { + size_t zlen; + char *z85 = pcp_z85_encode(buffer_get(exported_pk), buffer_size(exported_pk), &zlen); + fprintf(out, "%s\r\n%s\r\n%s\r\n", EXP_PK_HEADER, z85, EXP_PK_FOOTER); + FILE *t = fopen("binexp", "wb+"); + fwrite(buffer_get(exported_pk), 1, buffer_size(exported_pk), t); + fclose(t); + free(z85); + } + else + fwrite(buffer_get(exported_pk), 1, buffer_size(exported_pk), out); + buffer_free(exported_pk); + fprintf(stderr, "public key exported.\n"); } } - - if(out != NULL) { - /* scip */ - /* printf("EXPORT:\n"); */ - /* pcpprint_bin(stdout, key, PCP_RAW_PUBKEYSIZE); printf("\n"); */ - pcppubkey_print(key, out, pbpcompat); - if(pbpcompat) - fprintf(stderr, "public key exported in PBP format.\n"); - else - fprintf(stderr, "public key exported.\n"); + else { + /* FIXME: export foreign keys unsupported yet */ + fatal("Exporting foreign public keys in native format unsupported yet"); + goto errpcpexpu1; } - - free(key); } + else if(format == EXP_FORMAT_PBP) { + if(is_foreign == 0) { + exported_pk = pcp_export_pbp_pub(sk); + if(exported_pk != NULL) { + /* PBP format requires armoring always */ + size_t zlen; + char *z85pbp = pcp_z85_encode(buffer_get(exported_pk), buffer_size(exported_pk), &zlen); + fprintf(out, "%s", z85pbp); + free(z85pbp); + buffer_free(exported_pk); + fprintf(stderr, "public key exported in PBP format.\n"); + } + } + else { + fatal("Exporting foreign public keys in PBP format not possible"); + goto errpcpexpu1; + } + } + +errpcpexpu1: + buffer_free(exported_pk); } @@ -373,8 +428,9 @@ int pcp_importsecret (vault_t *vault, FILE *in) { } -int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) { +int pcp_importpublic (vault_t *vault, FILE *in) { pcp_pubkey_t *pub = NULL; + int pbpcompat = 0; if(pbpcompat == 1) { char *date = NULL; char *parts = NULL; @@ -626,67 +682,3 @@ char *pcp_find_id_byrec(char *recipient) { -/* - Experimental RFC4880-alike public key export. Once stable and - flexible enough, this will become the PCP default, I hope. */ -void pcp_exportpublic2(char *passwd, char *outfile, int armor) { - pcp_pubkey_t *key = NULL; - - pcp_key_t *s = NULL; - s = pcp_find_primary_secret(); - if(s == NULL) { - fatal("There's no primary secret key in the vault %s!\n", vault->filename); - free(s); - } - else { - key = pcpkey_pub_from_secret(s); - } - - if(key != NULL) { - FILE *out; - if(outfile == NULL) { - out = stdout; - } - else { - if((out = fopen(outfile, "wb+")) == NULL) { - fatal("Could not create output file %s", outfile); - out = NULL; - } - } - - if(out != NULL) { - pcp_key_t *sk = pcp_find_primary_secret(); - if(sk != NULL) { - char *passphrase; - pcp_readpass(&passphrase, "Enter passphrase to decrypt your secret key for signing the export", NULL, 1); - - sk = pcpkey_decrypt(sk, passphrase); - if(sk != NULL) { - Buffer *exported_pk = pcp_get_rfc_pub(key, sk); - if(exported_pk != NULL) { - if(armor == 1) { - size_t zlen; - char *z85 = pcp_z85_encode(buffer_get(exported_pk), buffer_size(exported_pk), &zlen); - fprintf(out, "%s\r\n%s\r\n%s\r\n", EXP_PK_HEADER, z85, EXP_PK_FOOTER); - free(z85); - } - else - fwrite(buffer_get(exported_pk), 1, buffer_size(exported_pk), out); - - fclose(out); - if(debug) { - buffer_dump(exported_pk); - buffer_info(exported_pk); - pcp_dumppubkey(key); - } - buffer_free(exported_pk); - } - } - - free(passphrase); - } - - free(key); - } - } -} diff --git a/src/keymgmt.h b/src/keymgmt.h index f0d72e7..fdaf086 100644 --- a/src/keymgmt.h +++ b/src/keymgmt.h @@ -49,18 +49,20 @@ char *pcp_getstdin(const char *prompt); int pcp_storekey (pcp_key_t *key); void pcp_keygen(); void pcp_listkeys(); + void pcp_exportsecret(char *keyid, int useid, char *outfile); void pcp_exportsecretkey(pcp_key_t *key, char *outfile); +void pcp_exportpublic(char *keyid, char *passwd, char *outfile, int format, int armor); + pcp_key_t *pcp_getrsk(pcp_key_t *s, char *recipient, char *passwd); -void pcp_exportpublic(char *keyid, char *recipient, char *passwd, char *outfile, int pbpcompat); char *pcp_normalize_id(char *keyid); pcp_key_t *pcp_find_primary_secret(); -int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat); + +int pcp_importpublic (vault_t *vault, FILE *in); int pcp_importsecret (vault_t *vault, FILE *in); + void pcpdelete_key(char *keyid); char *pcp_find_id_byrec(char *recipient); -/* Experimental: new rfc4880 style pk export */ -void pcp_exportpublic2(char *passwd, char *outfile, int armor); #endif /* _HAVE_KEYMGMT_H */ diff --git a/src/keyprint.c b/src/keyprint.c index a5c976f..bad8068 100644 --- a/src/keyprint.c +++ b/src/keyprint.c @@ -85,13 +85,14 @@ int pcptext_infile(char *infile) { } } + /* FIXME: can't determine keytype by using its size */ if(clen == PCP_RAW_PUBKEYSIZE) { /* public key? */ pcp_pubkey_t *key = (pcp_pubkey_t *)bin; pubkey2native(key); if(pcp_sanitycheck_pub(key) == 0) { fprintf(stdout, "%s is a public key file:\n", infile); - pcppubkey_print(key, stdout, 0); + // pcppubkey_print(key, stdout, 0); free(key); goto tdone; } @@ -127,7 +128,7 @@ void pcptext_key(char *keyid) { if(p != NULL) { if(debug) pcp_dumppubkey(p); - pcppubkey_print(p, stdout, 0); + pcppubkey_print(p, stdout); } else { fatal("No key with id 0x%s found!\n", keyid); @@ -175,6 +176,57 @@ void pcppubkey_printlineinfo(pcp_pubkey_t *key) { key->owner, key->mail); } +void pcppubkey_print(pcp_pubkey_t *key, FILE* out) { + size_t zlen; + struct tm *c; + time_t t = (time_t)key->ctime; + c = localtime(&t); + + fprintf(out, " Generated by: %s Version %d.%d.%d\n", + PCP_ME, PCP_VERSION_MAJOR, PCP_VERSION_MINOR, PCP_VERSION_PATCH); + + fprintf(out, " Cipher: %s\n", PCP_KEY_PRIMITIVE); + + fprintf(out, " Owner: %s\n", key->owner); + fprintf(out, " Mail: %s\n", key->mail); + + fprintf(out, " Key-ID: 0x%s\n", key->id); + fprintf(out, " Public-Key: %s\n", pcp_z85_encode(key->pub, 32, &zlen)); + + /* 2004-06-14T23:34:30. */ + fprintf(out, " Creation Time: %04d-%02d-%02dT%02d:%02d:%02d\n", + c->tm_year+1900, c->tm_mon+1, c->tm_mday, + c->tm_hour, c->tm_min, c->tm_sec); + + unsigned char *hash = pcppubkey_getchecksum(key); + fprintf(out, " Checksum: "); + + int i; + for ( i = 0;i <15 ;++i) fprintf(out, "%02X:",(unsigned int) hash[i]); + fprintf(out, "%02X", hash[15]); + fprintf(out, "\n "); + for ( i = 16;i <31 ;++i) fprintf(out, "%02X:",(unsigned int) hash[i]); + fprintf(out, "%02X", hash[31]); + fprintf(out, "\n"); + fprintf(out, " Serial Number: 0x%08X\n", key->serial); + fprintf(out, " Key Version: 0x%08X\n", key->version); + + char *r = pcppubkey_get_art(key); + fprintf(out, " Random Art ID: "); + for (i=0; ictime; - c = localtime(&t); - - if(pbpcompat == 1) { - pcp_key_t *secret = NULL; - secret = pcp_find_primary_secret(); - - if(secret == NULL) { - fatal("Could not find a secret key in vault %s!\n", vault->filename); - } - else { - char *passphrase; - pcp_readpass(&passphrase, - "Enter passphrase to decrypt your secret key for signing the export", NULL, 1); - - secret = pcpkey_decrypt(secret, passphrase); - if(secret != NULL) { - 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); - - 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)); - } - - /* 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); - - 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; - char *b85sig = ucmalloc(blen); - encode_85(b85sig, sig, siglen); - fprintf(out, "%s", b85sig); - free(b85sig); - free(sig); - } - free(blob); - } - } - } - else { - size_t zlen; - - /* printf("version: %08x\n", key->version); */ - - pubkey2be(key); - - void *blob = ucmalloc(PCP_RAW_PUBKEYSIZE); - pcp_pubkeyblob(blob, key); - char *z85encoded = pcp_z85_encode((unsigned char*)blob, PCP_RAW_PUBKEYSIZE, &zlen); - pubkey2native(key); - - free(blob); - - - - fprintf(out, "%s\n", PCP_PUBKEY_HEADER); - - fprintf(out, " Generated by: %s Version %d.%d.%d\n", - PCP_ME, PCP_VERSION_MAJOR, PCP_VERSION_MINOR, PCP_VERSION_PATCH); - - fprintf(out, " Cipher: %s\n", PCP_KEY_PRIMITIVE); - - fprintf(out, " Owner: %s\n", key->owner); - fprintf(out, " Mail: %s\n", key->mail); - - fprintf(out, " Key-ID: 0x%s\n", key->id); - fprintf(out, " Public-Key: %s\n", pcp_z85_encode(key->pub, 32, &zlen)); - - /* 2004-06-14T23:34:30. */ - fprintf(out, " Creation Time: %04d-%02d-%02dT%02d:%02d:%02d\n", - c->tm_year+1900, c->tm_mon+1, c->tm_mday, - c->tm_hour, c->tm_min, c->tm_sec); - - unsigned char *hash = pcppubkey_getchecksum(key); - fprintf(out, " Checksum: "); - - int i; - for ( i = 0;i <15 ;++i) fprintf(out, "%02X:",(unsigned int) hash[i]); - fprintf(out, "%02X", hash[15]); - fprintf(out, "\n "); - for ( i = 16;i <31 ;++i) fprintf(out, "%02X:",(unsigned int) hash[i]); - fprintf(out, "%02X", hash[31]); - fprintf(out, "\n"); - fprintf(out, " Serial Number: 0x%08X\n", key->serial); - fprintf(out, " Key Version: 0x%08X\n", key->version); - - char *r = pcppubkey_get_art(key); - fprintf(out, " Random Art ID: "); - for (i=0; i