static int read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf) { int res; PGP_PubKey *pk = NULL; res = _pgp_read_public_key(pkt, &pk); if (res < 0) goto err; /* skip secret key part, if it exists */ res = pgp_skip_packet(pkt); if (res < 0) goto err; /* is it encryption key */ switch (pk->algo) { case PGP_PUB_ELG_ENCRYPT: case PGP_PUB_RSA_ENCRYPT: case PGP_PUB_RSA_ENCRYPT_SIGN: memcpy(keyid_buf, pk->key_id, 8); res = 1; break; default: res = 0; } err: pgp_key_free(pk); return res; }
int pgp_free(PGP_Context *ctx) { if (ctx->pub_key) pgp_key_free(ctx->pub_key); px_memset(ctx, 0, sizeof *ctx); px_free(ctx); return 0; }
static int internal_read_key(PullFilter *src, PGP_PubKey **pk_p, const uint8 *psw, int psw_len, int pubtype) { PullFilter *pkt = NULL; int res; uint8 tag; int len; PGP_PubKey *enc_key = NULL; PGP_PubKey *pk = NULL; int got_main_key = 0; /* * Search for encryption key. * * Error out on anything fancy. */ while (1) { res = pgp_parse_pkt_hdr(src, &tag, &len, 0); if (res <= 0) break; res = pgp_create_pkt_reader(&pkt, src, len, res, NULL); if (res < 0) break; switch (tag) { case PGP_PKT_PUBLIC_KEY: case PGP_PKT_SECRET_KEY: if (got_main_key) { res = PXE_PGP_MULTIPLE_KEYS; break; } got_main_key = 1; res = pgp_skip_packet(pkt); break; case PGP_PKT_PUBLIC_SUBKEY: if (pubtype != 0) res = PXE_PGP_EXPECT_SECRET_KEY; else res = _pgp_read_public_key(pkt, &pk); break; case PGP_PKT_SECRET_SUBKEY: if (pubtype != 1) res = PXE_PGP_EXPECT_PUBLIC_KEY; else res = process_secret_key(pkt, &pk, psw, psw_len); break; case PGP_PKT_SIGNATURE: case PGP_PKT_MARKER: case PGP_PKT_TRUST: case PGP_PKT_USER_ID: case PGP_PKT_USER_ATTR: case PGP_PKT_PRIV_61: res = pgp_skip_packet(pkt); break; default: px_debug("unknown/unexpected packet: %d", tag); res = PXE_PGP_UNEXPECTED_PKT; } pullf_free(pkt); pkt = NULL; if (pk != NULL) { if (res >= 0 && pk->can_encrypt) { if (enc_key == NULL) { enc_key = pk; pk = NULL; } else res = PXE_PGP_MULTIPLE_SUBKEYS; } if (pk) pgp_key_free(pk); pk = NULL; } if (res < 0) break; } if (pkt) pullf_free(pkt); if (res < 0) { if (enc_key) pgp_key_free(enc_key); return res; } if (!enc_key) res = PXE_PGP_NO_USABLE_KEY; else *pk_p = enc_key; return res; }
static int process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p, const uint8 *key, int key_len) { int res; int hide_type; int cipher_algo; int bs; uint8 iv[512]; PullFilter *pf_decrypt = NULL, *pf_key; PGP_CFB *cfb = NULL; PGP_S2K s2k; PGP_PubKey *pk; /* first read public key part */ res = _pgp_read_public_key(pkt, &pk); if (res < 0) return res; /* * is secret key encrypted? */ GETBYTE(pkt, hide_type); if (hide_type == HIDE_SHA1 || hide_type == HIDE_CKSUM) { if (key == NULL) return PXE_PGP_NEED_SECRET_PSW; GETBYTE(pkt, cipher_algo); res = pgp_s2k_read(pkt, &s2k); if (res < 0) return res; res = pgp_s2k_process(&s2k, cipher_algo, key, key_len); if (res < 0) return res; bs = pgp_get_cipher_block_size(cipher_algo); if (bs == 0) { px_debug("unknown cipher algo=%d", cipher_algo); return PXE_PGP_UNSUPPORTED_CIPHER; } res = pullf_read_fixed(pkt, bs, iv); if (res < 0) return res; /* * create decrypt filter */ res = pgp_cfb_create(&cfb, cipher_algo, s2k.key, s2k.key_len, 0, iv); if (res < 0) return res; res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt); if (res < 0) return res; pf_key = pf_decrypt; } else if (hide_type == HIDE_CLEAR) { pf_key = pkt; } else { px_debug("unknown hide type"); return PXE_PGP_KEYPKT_CORRUPT; } /* read secret key */ switch (pk->algo) { case PGP_PUB_RSA_SIGN: case PGP_PUB_RSA_ENCRYPT: case PGP_PUB_RSA_ENCRYPT_SIGN: res = pgp_mpi_read(pkt, &pk->sec.rsa.d); if (res < 0) break; res = pgp_mpi_read(pkt, &pk->sec.rsa.p); if (res < 0) break; res = pgp_mpi_read(pkt, &pk->sec.rsa.q); if (res < 0) break; res = pgp_mpi_read(pkt, &pk->sec.rsa.u); if (res < 0) break; break; case PGP_PUB_ELG_ENCRYPT: res = pgp_mpi_read(pf_key, &pk->sec.elg.x); break; case PGP_PUB_DSA_SIGN: res = pgp_mpi_read(pf_key, &pk->sec.dsa.x); break; default: px_debug("unknown public algo: %d", pk->algo); res = PXE_PGP_KEYPKT_CORRUPT; } /* read checksum / sha1 */ if (res >= 0) { if (hide_type == HIDE_SHA1) res = check_key_sha1(pf_key, pk); else res = check_key_cksum(pf_key, pk); } if (res >= 0) res = pgp_expect_packet_end(pf_key); if (pf_decrypt) pullf_free(pf_decrypt); if (cfb) pgp_cfb_free(cfb); if (res < 0) pgp_key_free(pk); else *pk_p = pk; return res; }
int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p) { int res; PGP_PubKey *pk; res = pgp_key_alloc(&pk); if (res < 0) return res; /* get version */ GETBYTE(pkt, pk->ver); if (pk->ver != 4) { res = PXE_PGP_NOT_V4_KEYPKT; goto out; } /* read time */ res = pullf_read_fixed(pkt, 4, pk->time); if (res < 0) goto out; /* pubkey algorithm */ GETBYTE(pkt, pk->algo); switch (pk->algo) { case PGP_PUB_DSA_SIGN: res = pgp_mpi_read(pkt, &pk->pub.dsa.p); if (res < 0) break; res = pgp_mpi_read(pkt, &pk->pub.dsa.q); if (res < 0) break; res = pgp_mpi_read(pkt, &pk->pub.dsa.g); if (res < 0) break; res = pgp_mpi_read(pkt, &pk->pub.dsa.y); if (res < 0) break; res = calc_key_id(pk); break; case PGP_PUB_RSA_SIGN: case PGP_PUB_RSA_ENCRYPT: case PGP_PUB_RSA_ENCRYPT_SIGN: res = pgp_mpi_read(pkt, &pk->pub.rsa.n); if (res < 0) break; res = pgp_mpi_read(pkt, &pk->pub.rsa.e); if (res < 0) break; res = calc_key_id(pk); if (pk->algo != PGP_PUB_RSA_SIGN) pk->can_encrypt = 1; break; case PGP_PUB_ELG_ENCRYPT: res = pgp_mpi_read(pkt, &pk->pub.elg.p); if (res < 0) break; res = pgp_mpi_read(pkt, &pk->pub.elg.g); if (res < 0) break; res = pgp_mpi_read(pkt, &pk->pub.elg.y); if (res < 0) break; res = calc_key_id(pk); pk->can_encrypt = 1; break; default: px_debug("unknown public algo: %d", pk->algo); res = PXE_PGP_UNKNOWN_PUBALGO; } out: if (res < 0) pgp_key_free(pk); else *pk_p = pk; return res; }
int dc_pgp_create_keypair(dc_context_t* context, const char* addr, dc_key_t* ret_public_key, dc_key_t* ret_private_key) { int success = 0; pgp_key_t seckey; pgp_key_t pubkey; pgp_key_t subkey; uint8_t subkeyid[PGP_KEY_ID_SIZE]; uint8_t* user_id = NULL; pgp_memory_t* pubmem = pgp_memory_new(); pgp_memory_t* secmem = pgp_memory_new(); pgp_output_t* pubout = pgp_output_new(); pgp_output_t* secout = pgp_output_new(); memset(&seckey, 0, sizeof(pgp_key_t)); memset(&pubkey, 0, sizeof(pgp_key_t)); memset(&subkey, 0, sizeof(pgp_key_t)); if (context==NULL || addr==NULL || ret_public_key==NULL || ret_private_key==NULL || pubmem==NULL || secmem==NULL || pubout==NULL || secout==NULL) { goto cleanup; } /* Generate User ID. By convention, this is the e-mail-address in angle brackets. As the user-id is only decorative in Autocrypt and not needed for Delta Chat, so we _could_ just use sth. that looks like an e-mail-address. This would protect the user's privacy if someone else uploads the keys to keyservers. However, as eg. Enigmail displayes the user-id in "Good signature from <user-id>, for now, we decided to leave the address in the user-id */ #if 0 user_id = (uint8_t*)dc_mprintf("<%08X@%08X.org>", (int)random(), (int)random()); #else user_id = (uint8_t*)dc_mprintf("<%s>", addr); #endif /* generate two keypairs */ if (!pgp_rsa_generate_keypair(&seckey, DC_KEYGEN_BITS, DC_KEYGEN_E, NULL, NULL, NULL, 0) || !pgp_rsa_generate_keypair(&subkey, DC_KEYGEN_BITS, DC_KEYGEN_E, NULL, NULL, NULL, 0)) { goto cleanup; } /* Create public key, bind public subkey to public key ------------------------------------------------------------------------ */ pubkey.type = PGP_PTAG_CT_PUBLIC_KEY; pgp_pubkey_dup(&pubkey.key.pubkey, &seckey.key.pubkey); memcpy(pubkey.pubkeyid, seckey.pubkeyid, PGP_KEY_ID_SIZE); pgp_fingerprint(&pubkey.pubkeyfpr, &seckey.key.pubkey, 0); add_selfsigned_userid(&seckey, &pubkey, (const uint8_t*)user_id, 0/*never expire*/); EXPAND_ARRAY((&pubkey), subkey); { pgp_subkey_t* p = &pubkey.subkeys[pubkey.subkeyc++]; pgp_pubkey_dup(&p->key.pubkey, &subkey.key.pubkey); pgp_keyid(subkeyid, PGP_KEY_ID_SIZE, &pubkey.key.pubkey, PGP_HASH_SHA1); memcpy(p->id, subkeyid, PGP_KEY_ID_SIZE); } EXPAND_ARRAY((&pubkey), subkeysig); add_subkey_binding_signature(&pubkey.subkeysigs[pubkey.subkeysigc++], &pubkey, &subkey, &seckey); /* Create secret key, bind secret subkey to secret key ------------------------------------------------------------------------ */ EXPAND_ARRAY((&seckey), subkey); { pgp_subkey_t* p = &seckey.subkeys[seckey.subkeyc++]; pgp_seckey_dup(&p->key.seckey, &subkey.key.seckey); pgp_keyid(subkeyid, PGP_KEY_ID_SIZE, &seckey.key.pubkey, PGP_HASH_SHA1); memcpy(p->id, subkeyid, PGP_KEY_ID_SIZE); } EXPAND_ARRAY((&seckey), subkeysig); add_subkey_binding_signature(&seckey.subkeysigs[seckey.subkeysigc++], &seckey, &subkey, &seckey); /* Done with key generation, write binary keys to memory ------------------------------------------------------------------------ */ pgp_writer_set_memory(pubout, pubmem); if (!pgp_write_xfer_key(pubout, &pubkey, 0/*armored*/) || pubmem->buf==NULL || pubmem->length <= 0) { goto cleanup; } pgp_writer_set_memory(secout, secmem); if (!pgp_write_xfer_key(secout, &seckey, 0/*armored*/) || secmem->buf==NULL || secmem->length <= 0) { goto cleanup; } dc_key_set_from_binary(ret_public_key, pubmem->buf, pubmem->length, DC_KEY_PUBLIC); dc_key_set_from_binary(ret_private_key, secmem->buf, secmem->length, DC_KEY_PRIVATE); success = 1; cleanup: if (pubout) { pgp_output_delete(pubout); } if (secout) { pgp_output_delete(secout); } if (pubmem) { pgp_memory_free(pubmem); } if (secmem) { pgp_memory_free(secmem); } pgp_key_free(&seckey); /* not: pgp_keydata_free() which will also free the pointer itself (we created it on the stack) */ pgp_key_free(&pubkey); pgp_key_free(&subkey); free(user_id); return success; }