/* * Get somebody's encrypted secret key from the database, using the given * passwd to decrypt it. */ int getsecretkey(char *netname, char *secretkey, char *passwd) { char lookup[3 * HEXKEYBYTES]; char *p; if (secretkey == NULL) return (0); if (!getpublicandprivatekey(netname, lookup)) return (0); p = strchr(lookup, ':'); if (p == NULL) { return (0); } p++; if (!xdecrypt(p, passwd)) { return (0); } if (memcmp(p, p + HEXKEYBYTES, KEYCHECKSUMSIZE) != 0) { secretkey[0] = '\0'; return (1); } p[HEXKEYBYTES] = '\0'; (void) strncpy(secretkey, p, HEXKEYBYTES); secretkey[HEXKEYBYTES] = '\0'; return (1); }
static void read_confirm(struct rcontext* rcontext, const struct proto* proto) { char buf[1500]; ssize_t olength = 0; struct cipher_context *cipher; olength = xdecrypt(rcontext->config, rcontext->config->keyX, proto->rid.value, proto->rid.length, buf); if (olength < 0) { return; } cipher = verify_challenge(rcontext->config, &rcontext->from, &rcontext->endpoint->local, rcontext->session ? rcontext->session->rkey : 0, proto->rid.value, proto->rid.length); if (cipher == 0) { fprintf(stderr, "!! verify_challenge failed\n"); return; } /* update session*/ if (rcontext->rendpoint == 0) { rcontext->rendpoint = rendpoint_update(rcontext->config, &rcontext->from, 0); } if (rcontext->session == 0) { fprintf(stderr, "Confirm accepted. Creating new session\n"); rcontext->session = session_create(rcontext->config, rcontext->endpoint, rcontext->rendpoint); } else { fprintf(stderr, "confirm accepted\n"); } if (rcontext->session->rkey) { cipher_context_free(rcontext->session->rkey); } rcontext->session->rkey = cipher_context_create(rcontext->config->cipher, buf); write_accept(rcontext); }
enum nss_status _nss_nis_getsecretkey (const char *netname, char *skey, char *passwd, int *errnop) { enum nss_status retval; char buf[2 * (HEXKEYBYTES + 1)]; char *domain, *result; int len; skey[0] = 0; if (netname == NULL || passwd == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } domain = strchr (netname, '@'); if (!domain) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } ++domain; retval = yperr2nss (yp_match (domain, "publickey.byname", netname, strlen (netname), &result, &len)); if (retval != NSS_STATUS_SUCCESS) { if (retval == NSS_STATUS_NOTFOUND) *errnop = ENOENT; else if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } if (result != NULL) { char *p = strchr (result, ':'); if (p == NULL) return NSS_STATUS_SUCCESS; ++p; strncpy (buf, p, 2 * (HEXKEYBYTES + 1)); buf[2 * (HEXKEYBYTES + 1)] = '\0'; if (!xdecrypt (buf, passwd)) return NSS_STATUS_SUCCESS; if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0) return NSS_STATUS_SUCCESS; buf[HEXKEYBYTES] = '\0'; strcpy (skey, buf); } return NSS_STATUS_SUCCESS; }
enum nss_status _nss_nis_getsecretkey (const char *netname, char *skey, char *passwd, int *errnop) { skey[0] = 0; if (netname == NULL || passwd == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } char *domain = strchr (netname, '@'); if (domain == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } ++domain; char *result; int len; int yperr = yp_match (domain, "publickey.byname", netname, strlen (netname), &result, &len); if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { enum nss_status retval = yperr2nss (yperr); if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } if (result != NULL) { char *p = strchr (result, ':'); if (p != NULL) { char buf[2 * (HEXKEYBYTES + 1)]; ++p; strncpy (buf, p, 2 * (HEXKEYBYTES + 1)); buf[2 * HEXKEYBYTES + 1] = '\0'; if (xdecrypt (buf, passwd) && memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) == 0) { buf[HEXKEYBYTES] = '\0'; strcpy (skey, buf); } } free (result); } return NSS_STATUS_SUCCESS; }
struct cipher_context* verify_challenge(struct master_config* config, struct udpaddress* remote, struct udpaddress* local, struct cipher_context* oldkey, char* in, ssize_t ilength) { char obuf[1500]; char token[1500]; ssize_t tlength, olength; olength = xdecrypt(config, config->keyX, in, ilength, obuf); if (olength < 0) { return 0; } tlength = create_challenge(config, remote, local, oldkey, obuf, token); if (tlength != olength) { return 0; } if (memcmp(token, obuf, tlength) != 0) { return 0; } return cipher_context_create(config->cipher, obuf); }
enum nss_status _nss_files_getsecretkey (const char *netname, char *skey, char *passwd, int *errnop) { enum nss_status status; char buf[HEXKEYBYTES + KEYCHECKSUMSIZE + 16]; skey[0] = 0; status = search (netname, buf, errnop, 1); if (status != NSS_STATUS_SUCCESS) return status; if (!xdecrypt (buf, passwd)) return NSS_STATUS_SUCCESS; if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0) return NSS_STATUS_SUCCESS; buf[HEXKEYBYTES] = 0; strcpy (skey, buf); return NSS_STATUS_SUCCESS; }
int vpn_recv(int fd, vpn_crypt_t *cry, vpn_proto_t type, void *buf, size_t buflen) { vpn_hdr_t hdr; gcry_cipher_hd_t hd = NULL; char bigpack[VPN_BIGPACKET], decpack[VPN_BIGPACKET], xiv[256], *s; int rr, rd, rc, rx; switch(type) { case VPN_CLIENT: hd = cry->hsrc; break; case VPN_SERVER: hd = cry->hdst; } memset(bigpack, 0, sizeof(bigpack)); memset(decpack, 0, sizeof(decpack)); /* read packet header */ memset(&hdr, 0, sizeof(hdr)); rr = recv(fd, &hdr, sizeof(hdr), 0); if(rr == -1) return rr; else if(!rr) return xmsg(0, VPN_DEBUG|VPN_INFO, "vpn_recv: lost connection, peer disconnected\n"); else if(rr != sizeof(hdr)) return xmsg(-1, VPN_DEBUG|VPN_INFO, "vpn_recv: partial recv of header not allowed\n"); xmsg(0, VPN_DEBUG, "received %d bytes header, checksum=%d and pad=%d\n", rr, hdr.checksum, hdr.pad); if(hdr.checksum > sizeof(bigpack)) return xmsg(-1, VPN_DEBUG|VPN_INFO, "packet too big: header checksum is %d\n", hdr.checksum); /* read packet data */ s = bigpack; rc = hdr.checksum; rx = 0; do { rr = safe_recv(fd, s, rc); if(rr == -1) return rr; else if(!rr) return xmsg(0, VPN_DEBUG|VPN_INFO, "vpn_recv: lost connection, peer disconnected\n"); xmsg(0, VPN_DEBUG, "read %d bytes of packet...\n", rr); s += rr; rx += rr; rc -= rr; } while(rx < hdr.checksum); /* generate iv to decrypt */ if(!cry->rndrecv) cry->rndrecv = initial_iv_random; memset(xiv, 0, sizeof(xiv)); gen_iv(xiv, cry->blklen, cry->rndrecv); /* xmsg(0, VPN_DEBUG, "recv using iv: %s\n", xiv); */ /* decrypt */ rd = xdecrypt(hd, cry->blklen, xiv, decpack, sizeof(decpack), bigpack, hdr.checksum); if(rd == -1 || rd != hdr.checksum) return xmsg(-1, VPN_DEBUG|VPN_INFO, "vpn_recv: cannot decrypt packet (%d != %d)\n", rd, hdr.checksum); /* copy data to user */ memcpy(buf, decpack, hdr.checksum - hdr.pad); /* set next iv */ cry->rndrecv = hdr.checksum - hdr.pad; return hdr.checksum - hdr.pad; }
int main(int argc, char **argv) { char name[MAXNETNAMELEN+1]; char public[HEXKEYBYTES + 1]; char secret[HEXKEYBYTES + 1]; char crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE + 1]; char crypt2[HEXKEYBYTES + KEYCHECKSUMSIZE + 1]; int status; char *pass; struct passwd *pw; uid_t uid; int force = 0; int ch; #ifdef YP char *master; #endif while ((ch = getopt(argc, argv, "f")) != -1) switch(ch) { case 'f': force = 1; break; default: usage(); } argc -= optind; argv += optind; if (argc != 0) usage(); #ifdef YP yp_get_default_domain(&domain); if (yp_master(domain, PKMAP, &master) != 0) errx(1, "can't find master of publickey database"); #endif uid = getuid() /*geteuid()*/; if (uid == 0) { if (host2netname(name, NULL, NULL) == 0) errx(1, "cannot convert hostname to netname"); } else { if (user2netname(name, uid, NULL) == 0) errx(1, "cannot convert username to netname"); } printf("Generating new key for %s.\n", name); if (!force) { if (uid != 0) { #ifdef YPPASSWD pw = ypgetpwuid(uid); #else pw = getpwuid(uid); #endif if (pw == NULL) { #ifdef YPPASSWD errx(1, "no NIS password entry found: can't change key"); #else errx(1, "no password entry found: can't change key"); #endif } } else { pw = getpwuid(0); if (pw == NULL) errx(1, "no password entry found: can't change key"); } } pass = getpass("Password:"******"invalid password"); } #else force = 1; /* Make this mandatory */ #endif genkeys(public, secret, pass); memcpy(crypt1, secret, HEXKEYBYTES); memcpy(crypt1 + HEXKEYBYTES, secret, KEYCHECKSUMSIZE); crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE] = 0; xencrypt(crypt1, pass); if (force) { memcpy(crypt2, crypt1, HEXKEYBYTES + KEYCHECKSUMSIZE + 1); xdecrypt(crypt2, getpass("Retype password:"******"password incorrect"); } #ifdef YP printf("Sending key change request to %s...\n", master); #endif status = setpublicmap(name, public, crypt1); if (status != 0) { #ifdef YP errx(1, "unable to update NIS database (%u): %s", status, yperr_string(status)); #else errx(1, "unable to update publickey database"); #endif } if (uid == 0) { /* * Root users store their key in /etc/$ROOTKEY so * that they can auto reboot without having to be * around to type a password. Storing this in a file * is rather dubious: it should really be in the EEPROM * so it does not go over the net. */ int fd; fd = open(ROOTKEY, O_WRONLY|O_TRUNC|O_CREAT, 0); if (fd < 0) { warn("%s", ROOTKEY); } else { char newline = '\n'; if (write(fd, secret, strlen(secret)) < 0 || write(fd, &newline, sizeof(newline)) < 0) warn("%s: write", ROOTKEY); } } if (key_setsecret(secret) < 0) errx(1, "unable to login with new secret key"); printf("Done.\n"); exit(0); /* NOTREACHED */ }
void interface_socket_callback(evutil_socket_t fd, short type, struct endpoint* endpoint) { struct rcontext rcontext; char ibuf[1500]; char obuf[1500]; char buf1[128], buf2[128]; ssize_t ilength, olength; struct master_config* config = endpoint->config; ilength = datagram_read(fd, ibuf, sizeof(ibuf), &rcontext.from); if (ilength < 0) { return; } if (udpaddress_equals(&endpoint->local, &rcontext.from)) { return; } rcontext.endpoint = endpoint; rcontext.rendpoint = rendpoint_find_by_address(config, &rcontext.from); rcontext.session = session_find_by_address(endpoint->config, &endpoint->local, &rcontext.from); rcontext.config = config; fprintf(stderr, "read %d bytes %s <=> %s. session: %d, rendpoint: %d\n", (int)ilength, udpaddress_string(&rcontext.from, buf1), udpaddress_string(&endpoint->local, buf2), rcontext.session != 0, rcontext.rendpoint != 0); olength = -1; if (rcontext.session) { if (rcontext.session->key1) { rcontext.rkey = rcontext.session->key1; olength = xdecrypt(config, rcontext.session->key1, ibuf, ilength, obuf); if (olength > 0) { fprintf(stderr, "!!key1\n"); } } if (olength < 0 && rcontext.session->key2) { rcontext.rkey = rcontext.session->key2; olength = xdecrypt(config, rcontext.session->key2, ibuf, ilength, obuf); if (olength > 0) { fprintf(stderr, "!!key2\n"); } } } if (olength < 0) { rcontext.rkey = config->key0; olength = xdecrypt(config, config->key0, ibuf, ilength, obuf); if (olength > 0) { fprintf(stderr, "!!key0\n"); } } if (olength < 0) { fprintf(stderr, "!!decrypt failed\n"); return; } if (proto_decode(&rcontext.proto, obuf, olength) <= 0) { fprintf(stderr, "!!decode failed\n"); return; } switch (rcontext.proto.type) { case PROTO_OFFER: fprintf(stderr, "!!Received offer\n"); // key change read_offer(&rcontext, &rcontext.proto); break; case PROTO_CHALLENGE: fprintf(stderr, "!!Received challenge\n"); read_challenge(&rcontext, &rcontext.proto); break; case PROTO_CONFIRM: // key change confirmed fprintf(stderr, "!!Received confirm\n"); read_confirm(&rcontext, &rcontext.proto); break; case PROTO_ACCEPTED: fprintf(stderr, "!!Received accepted\n"); read_accept(&rcontext, &rcontext.proto); break; case PROTO_DATA: fprintf(stderr, "!!Received data\n"); if (rcontext.session == 0) { break; } if (rcontext.rkey == config->key0) { break; } read_data(&rcontext, &rcontext.proto); break; default: assert(0); break; } }