/* accept and process request form local client */ void process_client_request(int fd_un2) { int len, len_toreceive, len_received, len_tosend, len_sent; int rc, fd_in = 0; CLI_REQUEST creq; CLI_RESPONSE cresp; SRV_REQUEST sreq; SRV_RESPONSE sresp; SRV_MESSAGE smsg; char buf[2048]; char keyid[MAX_TAG_LEN + MAX_HOST_LEN + 10]; BIGNUM *bn_base = NULL, *bn_prime = NULL, *bn_private = NULL; unsigned char* public = NULL; int public_len; unsigned char* secret_key = NULL; int secret_key_len; memset(&cresp, 0, sizeof(cresp)); memset(&sreq, 0, sizeof(sreq)); memset(&smsg, 0, sizeof(smsg)); /* receive request - we can expect at least 7 first bytes to receive */ len = recv(fd_un2, buf, 7, 0); if (len < 0) { output(LOG_ERR, "recv failed. %s", strerror(errno)); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } else if (!len) return; len_received = len; len_toreceive = get_der_seq_size(buf); if (len_toreceive > sizeof(buf)) { output(LOG_ERR, "packet sent by client is too big"); cresp.status = MK_STATUS(SCOPE_CLIENT, ERR_MALFORMED); goto send; } /* get the rest */ while (len_toreceive > len_received) { len = len_toreceive - len_received; len = recv(fd_un2, &buf[len_received], len, 0); if (len < 0) { output(LOG_ERR, "recv failed. %s", strerror(errno)); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } else if (!len) return; len_received += len; } /* decode request message */ rc = decode_client_request(buf, len_received, &creq); if (rc) { cresp.status = MK_STATUS(SCOPE_CLIENT, rc); goto send; } /* check if parameters, flags are valid */ if (creq.version != CURRENT_PROTOCOL_VERSION) { output(LOG_ERR, "unsupported protocol version %d", creq.version); cresp.status = MK_STATUS(SCOPE_CLIENT, ERR_PROTOCOL); goto send; } if (check_flag_validity(creq.flags)) { output(LOG_ERR, "not allowed option combination"); cresp.status = MK_STATUS(SCOPE_CLIENT, ERR_INVALID_PARAM); goto send; } if (creq.reqType == CRT_ENUM_KEYS) { cresp.status = STATUS_SUCCESS; goto send; } else if (creq.reqType == CRT_REQUEST_KEY && (!creq.keyLen || creq.keyLen > MAX_KEY_LEN)) { output(LOG_ERR, "invalid size of requested key: %d", creq.keyLen); cresp.status = MK_STATUS(SCOPE_CLIENT, ERR_INVALID_PARAM); goto send; } /* make keyid */ sprintf(keyid, "%s@%s", creq.tag, creq.peer); /* process request */ if (creq.reqType == CRT_DELETE_KEY) { /* check for a key in database and delete it */ if (keydb_exists(keyid)) { rc = keydb_delete(keyid); if (rc) { output(LOG_ERR, "keydb_delete failed. %s", strerror(errno)); cresp.status = MK_STATUS(SCOPE_HOST, ERR_INTERNAL); } } else { output(LOG_ERR, "requested key does not exist: '%s'", keyid); cresp.status = MK_STATUS(SCOPE_HOST, ERR_KEY_NOT_EXISTS); } } /* here we block and get requested key */ else if (creq.flags & FLAG_INIT_KEY) { struct sockaddr_in peer_addr; char addr_accept[] = "0123456789."; PEER_ENTRY* pe; /* locate and check the peer */ pe = find_peer(creq.peer); if (!pe) { output(LOG_ERR, "peer '%s' is not available", creq.peer); cresp.status = MK_STATUS(SCOPE_HOST, ERR_NOT_AVAILABLE); goto send; } else if (!pe->allow) { output(LOG_ERR, "access denied for peer '%s'", creq.peer); cresp.status = MK_STATUS(SCOPE_HOST, ERR_ACCESS_DENIED); goto send; } /* generate secret, calculate public value */ rc = dh_init_group_params(conf_dh_group, &bn_prime, &bn_base); if (rc) { output(LOG_ERR, "dh_init_group_params failed"); cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } DUMP_BN(bn_prime, "prime "); DUMP_BN(bn_base, "base "); rc = dh_gen_private_public(conf_dh_group, bn_prime, bn_base, &bn_private, &public, &public_len); if (rc) { output(LOG_ERR, "dh_gen_private_public failed"); cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } DUMP_BN(bn_private, "priv-i"); DUMP_BIN(public, public_len, "publ-i"); /* fill-in request */ sreq.cookie = generate_unique_cookie(); sreq.keyLen = creq.keyLen; strncpy(sreq.tag, creq.tag, sizeof(sreq.tag)); strncpy(sreq.host, conf_host, sizeof(sreq.host)); strncpy(sreq.expires, creq.expires, sizeof(sreq.expires)); sreq.dhGroup = conf_dh_group; sreq.dhPublic_len = public_len; memcpy(sreq.dhPublic, public, public_len); smsg.tbsMsg_len = sizeof(smsg.tbsMsg); rc = encode_server_request(&sreq, smsg.tbsMsg, &smsg.tbsMsg_len); if (rc) { cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } /* fill-in request message */ smsg.version = CURRENT_PROTOCOL_VERSION; /* sign request if required */ if (pe->auth != AUTH_NONE) { rc = sign_message(pe, smsg.tbsMsg, smsg.tbsMsg_len, smsg.sigAlg, &smsg.sigAlg_len, smsg.sig, &smsg.sig_len); if (rc) { cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } } /* encode message */ len = sizeof(buf); rc = encode_server_message(&smsg, buf, &len); if (rc) { cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } /* get peer id & address, connect to socket and send the message */ /* is it ip address? */ if (strspn(creq.peer, addr_accept) == strlen(creq.peer)) { if (!inet_aton(creq.peer, &(peer_addr.sin_addr))) { output(LOG_ERR, "inet_aton failed"); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } } /* resolve dns */ else { struct hostent* h = gethostbyname(creq.peer); if (!h) { output(LOG_ERR, "gethostbyname failed"); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } peer_addr.sin_addr = *((struct in_addr*)h->h_addr); } peer_addr.sin_family = AF_INET; peer_addr.sin_port = htons(creq.port ? creq.port : DEFAULT_PORT); memset(peer_addr.sin_zero, 0, sizeof(peer_addr.sin_zero)); fd_in = socket(AF_INET, SOCK_STREAM, 0); if (!fd_in) { output(LOG_ERR, "socket failed. %s", strerror(errno)); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } rc = connect(fd_in, (struct sockaddr*)&peer_addr, sizeof(struct sockaddr)); if (rc == -1) { output(LOG_ERR, "connect failed. %s", strerror(errno)); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } /* send request */ len_sent = 0; len_tosend = len; while (len_tosend > len_sent) { len = len_tosend - len_sent; len = send(fd_in, &buf[len_sent], len, 0); if (len < 0) { output(LOG_ERR, "send failed/connection closed by peer"); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } len_sent += len; } memset(&smsg, 0, sizeof(smsg)); /* receive response - we can expect at least 14 bytes to receive */ len = recv(fd_in, buf, 14, 0); if (len <= 0) { output(LOG_ERR, "recv failed/connection closed by peer"); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } len_received = len; len_toreceive = get_der_seq_size(buf); assert(len_toreceive <= sizeof(buf)); if (len_toreceive > sizeof(buf)) { output(LOG_ERR, "packet sent by peer is too big"); cresp.status = MK_STATUS(SCOPE_PEER, ERR_MALFORMED); goto send; } /* get the rest */ while (len_toreceive > len_received) { len = len_toreceive - len_received; len = recv(fd_in, &buf[len_received], len, 0); if (len < 0) { output(LOG_ERR, "recv failed/connection closed by peer"); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } len_received += len; } close(fd_in); fd_in = 0; /* decode response message */ rc = decode_server_message(buf, len_received, &smsg); if (rc) { cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } /* sanity check */ if (smsg.version != CURRENT_PROTOCOL_VERSION) { output(LOG_ERR, "unsupported protocol version %d", smsg.version); cresp.status = MK_STATUS(SCOPE_PEER, ERR_PROTOCOL); goto send; } /* verify signature if required */ if (smsg.sigAlg_len && smsg.sig_len) { rc = verify_signature(pe, smsg.tbsMsg, smsg.tbsMsg_len, smsg.sigAlg, smsg.sigAlg_len, smsg.sig, smsg.sig_len); if (rc) { cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } } else if (pe->auth != AUTH_NONE) { output(LOG_ERR, "response is not signed"); cresp.status = MK_STATUS(SCOPE_PEER, ERR_SIG_VERIFY); goto send; } /* decode response */ rc = decode_server_response(smsg.tbsMsg, smsg.tbsMsg_len, &sresp); if (rc) { cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } if (GET_ERR(sresp.status)) { output(LOG_ERR, "peer returned status 0x%0.2hx", sresp.status); cresp.status = MK_STATUS(SCOPE_PEER, GET_ERR(sresp.status)); goto send; } /* calculate shared secret, make a requested key */ rc = dh_get_secret(sresp.dhPublic, sresp.dhPublic_len, bn_private, bn_prime, &secret_key, &secret_key_len); if (rc) { output(LOG_ERR, "dh_get_secret failed"); cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } DUMP_BIN(sresp.dhPublic, sresp.dhPublic_len, "publ-r"); DUMP_BIN(secret_key, secret_key_len, "secr-i"); assert(secret_key_len >= BITS_TO_BYTES(creq.keyLen)); /* store a key to database */ if (creq.flags & FLAG_STORE_KEY) { char kval_buf[KEY_VAL_SIZE + MAX_KEY_LEN]; PKEY_VAL pkey_val = (PKEY_VAL)kval_buf; pkey_val->expires = gentime_to_time_t(creq.expires); if (pkey_val->expires == -1) { output(LOG_ERR, "cannot convert time value %s", creq.expires); cresp.status = MK_STATUS(SCOPE_HOST, ERR_INVALID_PARAM); goto send; } pkey_val->key_len = creq.keyLen; memcpy(pkey_val->key, secret_key, BITS_TO_BYTES(pkey_val->key_len)); rc = keydb_store(keyid, kval_buf, sizeof(KEY_VAL) + BITS_TO_BYTES(pkey_val->key_len)); if (rc) { output(LOG_ERR, "keydb_store failed. %s", strerror(errno)); cresp.status = MK_STATUS(SCOPE_HOST, ERR_INTERNAL); goto send; } output(LOG_INFO, "new key '%s' (%dbits) added, validity: %s", keyid, pkey_val->key_len, ctime(&pkey_val->expires)); } cresp.keyLen = creq.keyLen; memcpy(cresp.key, secret_key, BITS_TO_BYTES(cresp.keyLen)); cresp.status = STATUS_SUCCESS; } else {
/* Delete a certificate or an secret key from a key database. */ static int delete_one (ctrl_t ctrl, const char *username) { int rc = 0; KEYDB_SEARCH_DESC desc; KEYDB_HANDLE kh = NULL; ksba_cert_t cert = NULL; int duplicates = 0; int is_ephem = 0; rc = keydb_classify_name (username, &desc); if (rc) { log_error (_("certificate `%s' not found: %s\n"), username, gpg_strerror (rc)); gpgsm_status2 (ctrl, STATUS_DELETE_PROBLEM, "1", NULL); goto leave; } kh = keydb_new (0); if (!kh) { log_error ("keydb_new failed\n"); goto leave; } /* If the key is specified in a unique way, include ephemeral keys in the search. */ if ( desc.mode == KEYDB_SEARCH_MODE_FPR || desc.mode == KEYDB_SEARCH_MODE_FPR20 || desc.mode == KEYDB_SEARCH_MODE_FPR16 || desc.mode == KEYDB_SEARCH_MODE_KEYGRIP ) { is_ephem = 1; keydb_set_ephemeral (kh, 1); } rc = keydb_search (kh, &desc, 1); if (!rc) rc = keydb_get_cert (kh, &cert); if (!rc && !is_ephem) { unsigned char fpr[20]; gpgsm_get_fingerprint (cert, 0, fpr, NULL); next_ambigious: rc = keydb_search (kh, &desc, 1); if (rc == -1) rc = 0; else if (!rc) { ksba_cert_t cert2 = NULL; unsigned char fpr2[20]; /* We ignore all duplicated certificates which might have been inserted due to program bugs. */ if (!keydb_get_cert (kh, &cert2)) { gpgsm_get_fingerprint (cert2, 0, fpr2, NULL); ksba_cert_release (cert2); if (!memcmp (fpr, fpr2, 20)) { duplicates++; goto next_ambigious; } } rc = gpg_error (GPG_ERR_AMBIGUOUS_NAME); } } if (rc) { if (rc == -1) rc = gpg_error (GPG_ERR_NO_PUBKEY); log_error (_("certificate `%s' not found: %s\n"), username, gpg_strerror (rc)); gpgsm_status2 (ctrl, STATUS_DELETE_PROBLEM, "3", NULL); goto leave; } /* We need to search again to get back to the right position. */ rc = keydb_lock (kh); if (rc) { log_error (_("error locking keybox: %s\n"), gpg_strerror (rc)); goto leave; } do { keydb_search_reset (kh); rc = keydb_search (kh, &desc, 1); if (rc) { log_error ("problem re-searching certificate: %s\n", gpg_strerror (rc)); goto leave; } rc = keydb_delete (kh, duplicates ? 0 : 1); if (rc) goto leave; if (opt.verbose) { if (duplicates) log_info (_("duplicated certificate `%s' deleted\n"), username); else log_info (_("certificate `%s' deleted\n"), username); } } while (duplicates--); leave: keydb_release (kh); ksba_cert_release (cert); return rc; }