123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- #include <stdint.h>
- #include <string.h>
- #include "crypto.h"
- #include "crypto_dh.h"
- #include "crypto_verify_bytes.h"
- #include "keygen.h"
- #include "netpacket.h"
- #include "netproto.h"
- #include "sysendian.h"
- #include "tsnetwork.h"
- #include "warnp.h"
- static sendpacket_callback callback_register_send;
- static handlepacket_callback callback_register_challenge;
- static handlepacket_callback callback_register_response;
- /**
- * keygen_network_register(C):
- * Register a new machine key with the Tarsnap server.
- */
- int
- keygen_network_register(struct register_internal * C)
- {
- NETPACKET_CONNECTION * NPC;
- C->done = 0;
- C->donechallenge = 0;
- C->machinenum = (uint64_t)(-1);
- /* Open netpacket connection. */
- if ((NPC = netpacket_open(USERAGENT)) == NULL)
- goto err2;
- /* Ask the netpacket layer to send a request and get a response. */
- if (netpacket_op(NPC, callback_register_send, C))
- goto err3;
- /* Run event loop until an error occurs or we're done. */
- if (network_spin(&C->done))
- goto err3;
- /* Close netpacket connection. */
- if (netpacket_close(NPC))
- goto err2;
- /*
- * If we didn't respond to a challenge, the server's response must
- * have been a "no such user" error.
- */
- if ((C->donechallenge == 0) && (C->status != 1)) {
- netproto_printerr(NETPROTO_STATUS_PROTERR);
- goto err1;
- }
- /* The machine number should be -1 iff the status is nonzero. */
- if (((C->machinenum == (uint64_t)(-1)) && (C->status == 0)) ||
- ((C->machinenum != (uint64_t)(-1)) && (C->status != 0))) {
- netproto_printerr(NETPROTO_STATUS_PROTERR);
- goto err1;
- }
- /* Parse status returned by server. */
- switch (C->status) {
- case 0:
- /* Success! */
- break;
- case 1:
- warn0("No such user: %s", C->user);
- break;
- case 2:
- warn0("Incorrect password");
- break;
- case 3:
- warn0("Cannot register with server: "
- "Account balance for user %s is not positive", C->user);
- break;
- default:
- netproto_printerr(NETPROTO_STATUS_PROTERR);
- goto err2;
- }
- /* Shut down the network event loop. */
- network_fini();
- /* Success! */
- return (0);
- err3:
- netpacket_close(NPC);
- err2:
- warnp("Error registering with server");
- err1:
- /* Shut down the network event loop. */
- network_fini();
- /* Failure! */
- return (-1);
- }
- static int
- callback_register_send(void * cookie, NETPACKET_CONNECTION * NPC)
- {
- struct register_internal * C = cookie;
- /* Tell the server which user is trying to add a machine. */
- return (netpacket_register_request(NPC, C->user,
- callback_register_challenge));
- }
- static int
- callback_register_challenge(void * cookie, NETPACKET_CONNECTION * NPC,
- int status, uint8_t packettype, const uint8_t * packetbuf,
- size_t packetlen)
- {
- struct register_internal * C = cookie;
- uint8_t pub[CRYPTO_DH_PUBLEN];
- uint8_t priv[CRYPTO_DH_PRIVLEN];
- uint8_t K[CRYPTO_DH_KEYLEN];
- uint8_t keys[96];
- /* Handle errors. */
- if (status != NETWORK_STATUS_OK) {
- netproto_printerr(status);
- goto err0;
- }
- /*
- * Make sure we received the right type of packet. It is legal for
- * the server to send back a NETPACKET_REGISTER_RESPONSE at this
- * point; call callback_register_response to handle those. Note that
- * NETPACKET_REGISTER_RESPONSE at this point must be a "no such user"
- * response; we verify this in callback_register_response.
- */
- if (packettype == NETPACKET_REGISTER_RESPONSE)
- return (callback_register_response(cookie, NPC, status,
- packettype, packetbuf, packetlen));
- else if (packettype != NETPACKET_REGISTER_CHALLENGE) {
- netproto_printerr(NETPROTO_STATUS_PROTERR);
- goto err0;
- }
- /* Generate DH parameters from the password and salt. */
- if (crypto_passwd_to_dh(C->passwd, packetbuf, pub, priv)) {
- warnp("Could not generate DH parameter from password");
- goto err0;
- }
- /* Compute shared key. */
- if (crypto_dh_compute(&packetbuf[32], priv, K))
- goto err0;
- if (crypto_hash_data(CRYPTO_KEY_HMAC_SHA256, K, CRYPTO_DH_KEYLEN,
- C->register_key)) {
- warn0("Programmer error: "
- "SHA256 should never fail");
- goto err0;
- }
- /* Export access keys. */
- if (crypto_keys_raw_export_auth(keys))
- goto err0;
- /* Send challenge response packet. */
- if (netpacket_register_cha_response(NPC, keys, C->name,
- C->register_key, callback_register_response))
- goto err0;
- /* We've responded to a challenge. */
- C->donechallenge = 1;
- /* Success! */
- return (0);
- err0:
- /* Failure! */
- return (-1);
- }
- static int
- callback_register_response(void * cookie, NETPACKET_CONNECTION * NPC,
- int status, uint8_t packettype, const uint8_t * packetbuf,
- size_t packetlen)
- {
- struct register_internal * C = cookie;
- uint8_t hmac_actual[32];
- (void)NPC; /* UNUSED */
- (void)packetlen; /* UNUSED */
- /* Handle errors. */
- if (status != NETWORK_STATUS_OK) {
- netproto_printerr(status);
- goto err0;
- }
- /* Make sure we received the right type of packet. */
- if (packettype != NETPACKET_REGISTER_RESPONSE)
- goto err1;
- /*
- * If the challenge has not been responded to (i.e. this packet
- * arrived in response to a NETPACKET_REGISTER_REQUEST packet), this
- * should be a "no such user" response.
- */
- if ((C->donechallenge == 0) && (packetbuf[0] != 1))
- goto err1;
- /* Verify packet hmac. */
- if ((packetbuf[0] == 0) || (packetbuf[0] == 3)) {
- crypto_hash_data_key_2(C->register_key, 32, &packettype, 1,
- packetbuf, 9, hmac_actual);
- } else {
- memset(hmac_actual, 0, 32);
- }
- if (crypto_verify_bytes(hmac_actual, &packetbuf[9], 32))
- goto err1;
- /* Record status code and machine number returned by server. */
- C->status = packetbuf[0];
- C->machinenum = be64dec(&packetbuf[1]);
- /* We have received a response. */
- C->done = 1;
- /* Success! */
- return (0);
- err1:
- netproto_printerr(NETPROTO_STATUS_PROTERR);
- err0:
- /* Failure! */
- return (-1);
- }
|