/** * Process an HB_REQ message */ void handle_hb_request(const struct sockaddr_in *src, const unsigned char *packet) { struct uftp_h *header; struct hb_req_h *hbreq; unsigned char *keymod, *sig; struct hostent *hp; RSA_key_t key; unsigned char *verifydata, fingerprint[HMAC_LEN]; unsigned int verifylen, fplen, keylen, siglen; int resp; header = (struct uftp_h *)packet; hbreq = (struct hb_req_h *)(packet + sizeof(struct uftp_h)); if (!noname && (hp = gethostbyaddr((char *)&src->sin_addr, sizeof(struct in_addr), AF_INET))) { log(0, 0, "Received HB_REQ from %s (%s)", hp->h_name, inet_ntoa(src->sin_addr)); } else { log(0, 0, "Received HB_REQ from %s", inet_ntoa(src->sin_addr)); } if ((proxy_type == SERVER_PROXY) && have_down_fingerprint) { if ((down_addr.sin_addr.s_addr == src->sin_addr.s_addr) && down_addr.sin_port == src->sin_port) { resp = HB_AUTH_OK; } else if (down_nonce != ntohl(hbreq->nonce)) { resp = HB_AUTH_CHALLENGE; } else { keymod = (unsigned char *)hbreq + sizeof(struct hb_req_h); keylen = ntohs(hbreq->keylen); sig = keymod + keylen; siglen = ntohs(hbreq->siglen); // First check key fingerprint verifylen = 0; verifydata = calloc(sizeof(hbreq->keyexp) + keylen, 1); if (verifydata == NULL) { syserror(0, 0, "calloc failed!"); exit(1); } memcpy(verifydata, &hbreq->keyexp, sizeof(hbreq->keyexp)); verifylen += sizeof(hbreq->keyexp); memcpy(verifydata + verifylen, keymod, keylen); verifylen += keylen; hash(HASH_SHA1, verifydata, verifylen, fingerprint, &fplen); if (memcmp(down_fingerprint, fingerprint, fplen)) { log(0, 0, "Failed to verify HB_REQ fingerprint"); free(verifydata); resp = HB_AUTH_FAILED; goto end; } free(verifydata); // Then check signature if (!import_RSA_key(&key, ntohl(hbreq->keyexp), keymod, keylen)) { log(0, 0, "Failed to import public key from HB_REQ"); resp = HB_AUTH_FAILED; goto end; } if (!verify_RSA_sig(key, HASH_SHA1, (unsigned char *)&hbreq->nonce, sizeof(hbreq->nonce), sig, siglen)) { log(0, 0, "Failed to verify HB_REQ signature"); resp = HB_AUTH_FAILED; goto end; } down_addr = *src; log(0, 0, "Using %s:%d as downstream address:port", inet_ntoa(src->sin_addr), ntohs(src->sin_port)); down_nonce = rand(); resp = HB_AUTH_OK; } } else { resp = HB_AUTH_OK; } end: send_hb_response(src, resp); }
/** * Process an HB_REQ message */ void handle_hb_request(const union sockaddr_u *src, unsigned char *packet, unsigned packetlen) { struct hb_req_h *hbreq; unsigned char *keyblob, *sig; union key_t key; unsigned char fingerprint[HMAC_LEN]; unsigned int fplen, bloblen, siglen; char destname[INET6_ADDRSTRLEN], destport[PORTNAME_LEN]; int resp, rval; hbreq = (struct hb_req_h *)(packet + sizeof(struct uftp_h)); if ((rval = getnameinfo((const struct sockaddr *)src, family_len(*src), destname, sizeof(destname), destport, sizeof(destport), NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { log1(0, 0, 0, "getnameinfo failed: %s", gai_strerror(rval)); } if ((packetlen < sizeof(struct uftp_h) + (hbreq->hlen * 4)) || ((hbreq->hlen * 4) < sizeof(struct hb_req_h))) { log1(0,0,0, "Rejecting HB_REQ from %s: invalid message size", destname); return; } log2(0, 0, 0, "Received HB_REQ from %s", destname); if ((proxy_type == SERVER_PROXY) && have_down_fingerprint) { if (addr_equal(&down_addr, src)) { resp = HB_AUTH_OK; } else if (down_nonce != ntohl(hbreq->nonce)) { resp = HB_AUTH_CHALLENGE; } else { keyblob = (unsigned char *)hbreq + sizeof(struct hb_req_h); bloblen = ntohs(hbreq->bloblen); sig = keyblob + bloblen; siglen = ntohs(hbreq->siglen); // First check key fingerprint, then check signature if (keyblob[0] == KEYBLOB_RSA) { if (!import_RSA_key(&key.rsa, keyblob, bloblen)) { log1(0, 0, 0, "Failed to import public key from HB_REQ"); resp = HB_AUTH_FAILED; goto end; } hash(HASH_SHA1, keyblob, bloblen, fingerprint, &fplen); if (memcmp(down_fingerprint, fingerprint, fplen)) { log1(0, 0, 0, "Failed to verify HB_REQ fingerprint"); resp = HB_AUTH_FAILED; goto end; } if (!verify_RSA_sig(key.rsa, HASH_SHA1, (unsigned char *)&hbreq->nonce, sizeof(hbreq->nonce), sig, siglen)) { log1(0, 0, 0, "Failed to verify HB_REQ signature"); resp = HB_AUTH_FAILED; goto end; } } else { if (!import_EC_key(&key.ec, keyblob, bloblen, 0)) { log1(0, 0, 0, "Failed to import public key from HB_REQ"); resp = HB_AUTH_FAILED; goto end; } hash(HASH_SHA1, keyblob, bloblen, fingerprint, &fplen); if (memcmp(down_fingerprint, fingerprint, fplen)) { log1(0, 0, 0, "Failed to verify HB_REQ fingerprint"); resp = HB_AUTH_FAILED; goto end; } if (!verify_ECDSA_sig(key.ec, HASH_SHA1, (unsigned char *)&hbreq->nonce, sizeof(hbreq->nonce), sig, siglen)) { log1(0, 0, 0, "Failed to verify HB_REQ signature"); resp = HB_AUTH_FAILED; goto end; } } down_addr = *src; log2(0, 0, 0, "Using %s:%s as downstream address:port", destname, destport); down_nonce = rand32(); resp = HB_AUTH_OK; } } else { resp = HB_AUTH_OK; } end: send_hb_response(src, resp); }