/* add a key to a secret keyring */ int __ops_add_to_secring(__ops_keyring_t *keyring, const __ops_seckey_t *seckey) { const __ops_pubkey_t *pubkey; __ops_key_t *key; if (__ops_get_debug_level(__FILE__)) { fprintf(stderr, "__ops_add_to_secring\n"); } if (keyring->keyc > 0) { key = &keyring->keys[keyring->keyc - 1]; if (__ops_get_debug_level(__FILE__) && key->key.pubkey.alg == OPS_PKA_DSA && seckey->pubkey.alg == OPS_PKA_ELGAMAL) { fprintf(stderr, "__ops_add_to_secring: found elgamal seckey\n"); } } EXPAND_ARRAY(keyring, key); key = &keyring->keys[keyring->keyc++]; (void) memset(key, 0x0, sizeof(*key)); pubkey = &seckey->pubkey; __ops_keyid(key->sigid, OPS_KEY_ID_SIZE, pubkey, keyring->hashtype); __ops_fingerprint(&key->sigfingerprint, pubkey, keyring->hashtype); key->type = OPS_PTAG_CT_SECRET_KEY; key->key.seckey = *seckey; if (__ops_get_debug_level(__FILE__)) { fprintf(stderr, "__ops_add_to_secring: keyc %u\n", keyring->keyc); } return 1; }
/* add a key to a public keyring */ int __ops_add_to_pubring(__ops_keyring_t *keyring, const __ops_pubkey_t *pubkey, __ops_content_enum tag) { __ops_key_t *key; time_t duration; if (__ops_get_debug_level(__FILE__)) { fprintf(stderr, "__ops_add_to_pubring (type %u)\n", tag); } switch(tag) { case OPS_PTAG_CT_PUBLIC_KEY: EXPAND_ARRAY(keyring, key); key = &keyring->keys[keyring->keyc++]; duration = key->key.pubkey.duration; (void) memset(key, 0x0, sizeof(*key)); key->type = tag; __ops_keyid(key->sigid, OPS_KEY_ID_SIZE, pubkey, keyring->hashtype); __ops_fingerprint(&key->sigfingerprint, pubkey, keyring->hashtype); key->key.pubkey = *pubkey; key->key.pubkey.duration = duration; return 1; case OPS_PTAG_CT_PUBLIC_SUBKEY: /* subkey is not the first */ key = &keyring->keys[keyring->keyc - 1]; __ops_keyid(key->encid, OPS_KEY_ID_SIZE, pubkey, keyring->hashtype); duration = key->key.pubkey.duration; (void) memcpy(&key->enckey, pubkey, sizeof(key->enckey)); key->enckey.duration = duration; return 1; default: return 0; } }
/** \ingroup Core_Keys \brief Add User ID to key \param key Key to which to add User ID \param userid User ID to add \return Pointer to new User ID */ uint8_t * __ops_add_userid(__ops_key_t *key, const uint8_t *userid) { uint8_t **uidp; EXPAND_ARRAY(key, uid); /* initialise new entry in array */ uidp = &key->uids[key->uidc++]; *uidp = NULL; /* now copy it */ return __ops_copy_userid(uidp, userid); }
/** \ingroup Core_Keys \brief Add packet to key \param keydata Key to which to add packet \param packet Packet to add \return Pointer to new packet */ __ops_subpacket_t * __ops_add_subpacket(__ops_key_t *keydata, const __ops_subpacket_t *packet) { __ops_subpacket_t *subpktp; EXPAND_ARRAY(keydata, packet); /* initialise new entry in array */ subpktp = &keydata->packets[keydata->packetc++]; subpktp->length = 0; subpktp->raw = NULL; /* now copy it */ return __ops_copy_packet(subpktp, packet); }
/* append one keyring to another */ int __ops_append_keyring(__ops_keyring_t *keyring, __ops_keyring_t *newring) { unsigned i; for (i = 0 ; i < newring->keyc ; i++) { EXPAND_ARRAY(keyring, key); (void) memcpy(&keyring->keys[keyring->keyc], &newring->keys[i], sizeof(newring->keys[i])); keyring->keyc += 1; } return 1; }
/** \ingroup Core_Keys \brief Add packet to key \param keydata Key to which to add packet \param packet Packet to add \return Pointer to new packet */ ops_packet_t* ops_add_packet_to_keydata(ops_keydata_t* keydata, const ops_packet_t* packet) { ops_packet_t* new_pkt=NULL; EXPAND_ARRAY(keydata, packets); // initialise new entry in array new_pkt=&keydata->packets[keydata->npackets]; new_pkt->length=0; new_pkt->raw=NULL; // now copy it ops_copy_packet(new_pkt, packet); keydata->npackets++; return new_pkt; }
/** \ingroup Core_Keys \brief Add User ID to keydata \param keydata Key to which to add User ID \param userid User ID to add \return Pointer to new User ID */ ops_user_id_t* ops_add_userid_to_keydata(ops_keydata_t* keydata, const ops_user_id_t* userid) { ops_user_id_t* new_uid=NULL; EXPAND_ARRAY(keydata, uids); // initialise new entry in array new_uid=&keydata->uids[keydata->nuids]; new_uid->user_id=NULL; // now copy it ops_copy_userid(new_uid,userid); keydata->nuids++; return new_uid; }
/** \ingroup Core_Keys \brief Add signed User ID to key \param keydata Key to which to add signed User ID \param user_id User ID to add \param sigpacket Packet to add */ void ops_add_signed_userid_to_keydata(ops_keydata_t* keydata, const ops_user_id_t* user_id, const ops_packet_t* sigpacket) { //int i=0; ops_user_id_t * uid=NULL; ops_packet_t * pkt=NULL; uid=ops_add_userid_to_keydata(keydata, user_id); pkt=ops_add_packet_to_keydata(keydata, sigpacket); /* * add entry in sigs array to link the userid and sigpacket */ // and add ptr to it from the sigs array EXPAND_ARRAY(keydata, sigs); // setup new entry in array keydata->sigs[keydata->nsigs].userid=uid; keydata->sigs[keydata->nsigs].packet=pkt; keydata->nsigs++; }
static __ops_cb_ret_t cb_keyring_read(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo) { __ops_keyring_t *keyring; __ops_revoke_t *revocation; __ops_key_t *key; keyringcb_t *cb; cb = __ops_callback_arg(cbinfo); keyring = cb->keyring; switch (pkt->tag) { case OPS_PARSER_PTAG: case OPS_PTAG_CT_ENCRYPTED_SECRET_KEY: /* we get these because we didn't prompt */ break; case OPS_PTAG_CT_SIGNATURE_HEADER: key = &keyring->keys[keyring->keyc - 1]; EXPAND_ARRAY(key, subsig); key->subsigs[key->subsigc].uid = key->uidc - 1; (void) memcpy(&key->subsigs[key->subsigc].sig, &pkt->u.sig, sizeof(pkt->u.sig)); key->subsigc += 1; break; case OPS_PTAG_CT_SIGNATURE: key = &keyring->keys[keyring->keyc - 1]; EXPAND_ARRAY(key, subsig); key->subsigs[key->subsigc].uid = key->uidc - 1; (void) memcpy(&key->subsigs[key->subsigc].sig, &pkt->u.sig, sizeof(pkt->u.sig)); key->subsigc += 1; break; case OPS_PTAG_CT_TRUST: key = &keyring->keys[keyring->keyc - 1]; key->subsigs[key->subsigc - 1].trustlevel = pkt->u.ss_trust.level; key->subsigs[key->subsigc - 1].trustamount = pkt->u.ss_trust.amount; break; case OPS_PTAG_SS_KEY_EXPIRY: EXPAND_ARRAY(keyring, key); if (keyring->keyc > 0) { keyring->keys[keyring->keyc - 1].key.pubkey.duration = pkt->u.ss_time; } break; case OPS_PTAG_SS_ISSUER_KEY_ID: key = &keyring->keys[keyring->keyc - 1]; (void) memcpy(&key->subsigs[key->subsigc - 1].sig.info.signer_id, pkt->u.ss_issuer, sizeof(pkt->u.ss_issuer)); key->subsigs[key->subsigc - 1].sig.info.signer_id_set = 1; break; case OPS_PTAG_SS_CREATION_TIME: key = &keyring->keys[keyring->keyc - 1]; key->subsigs[key->subsigc - 1].sig.info.birthtime = pkt->u.ss_time; key->subsigs[key->subsigc - 1].sig.info.birthtime_set = 1; break; case OPS_PTAG_SS_EXPIRATION_TIME: key = &keyring->keys[keyring->keyc - 1]; key->subsigs[key->subsigc - 1].sig.info.duration = pkt->u.ss_time; key->subsigs[key->subsigc - 1].sig.info.duration_set = 1; break; case OPS_PTAG_SS_PRIMARY_USER_ID: key = &keyring->keys[keyring->keyc - 1]; key->uid0 = key->uidc - 1; break; case OPS_PTAG_SS_REVOCATION_REASON: key = &keyring->keys[keyring->keyc - 1]; if (key->uidc == 0) { /* revoke whole key */ key->revoked = 1; revocation = &key->revocation; } else { /* revoke the user id */ EXPAND_ARRAY(key, revoke); revocation = &key->revokes[key->revokec]; key->revokes[key->revokec].uid = key->uidc - 1; key->revokec += 1; } revocation->code = pkt->u.ss_revocation.code; revocation->reason = netpgp_strdup(__ops_show_ss_rr_code(pkt->u.ss_revocation.code)); break; case OPS_PTAG_CT_SIGNATURE_FOOTER: case OPS_PARSER_ERRCODE: break; default: break; } return OPS_RELEASE_MEMORY; }
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; }