diff --git a/libknet/handle.c b/libknet/handle.c index fa989d64..8dec9229 100644 --- a/libknet/handle.c +++ b/libknet/handle.c @@ -1,451 +1,449 @@ #include "config.h" #include #include #include #include #include #include #include "libknet-private.h" #include "nsscrypto.h" #define KNET_MAX_EVENTS 8 #define KNET_PING_TIMERES 200000 static void *_handle_tap_to_links_thread(void *data); static void *_handle_recv_from_links_thread(void *data); static void *_handle_heartbt_thread(void *data); knet_handle_t knet_handle_new(const struct knet_handle_cfg *knet_handle_cfg) { knet_handle_t knet_h; struct epoll_event ev; /* * validate incoming config request */ if (knet_handle_cfg == NULL) { errno = EINVAL; return NULL; } if (knet_handle_cfg->fd <= 0) { errno = EINVAL; return NULL; } if ((knet_h = malloc(sizeof(struct knet_handle))) == NULL) return NULL; memset(knet_h, 0, sizeof(struct knet_handle)); if (crypto_init(knet_h, knet_handle_cfg) < 0) goto exit_fail1; if ((knet_h->tap_to_links_buf = malloc(KNET_DATABUFSIZE))== NULL) goto exit_fail2; memset(knet_h->tap_to_links_buf, 0, KNET_DATABUFSIZE); if ((knet_h->recv_from_links_buf = malloc(KNET_DATABUFSIZE))== NULL) goto exit_fail3; memset(knet_h->recv_from_links_buf, 0, KNET_DATABUFSIZE); if ((knet_h->pingbuf = malloc(KNET_PINGBUFSIZE))== NULL) goto exit_fail4; memset(knet_h->pingbuf, 0, KNET_PINGBUFSIZE); if (pthread_rwlock_init(&knet_h->list_rwlock, NULL) != 0) goto exit_fail5; knet_h->sockfd = knet_handle_cfg->fd; knet_h->tap_to_links_epollfd = epoll_create(KNET_MAX_EVENTS); knet_h->recv_from_links_epollfd = epoll_create(KNET_MAX_EVENTS); knet_h->node_id = knet_handle_cfg->node_id; if ((knet_h->tap_to_links_epollfd < 0) || (knet_h->recv_from_links_epollfd < 0)) goto exit_fail6; if ((_fdset_cloexec(knet_h->tap_to_links_epollfd) != 0) || (_fdset_cloexec(knet_h->recv_from_links_epollfd != 0))) goto exit_fail6; memset(&ev, 0, sizeof(struct epoll_event)); ev.events = EPOLLIN; ev.data.fd = knet_h->sockfd; if (epoll_ctl(knet_h->tap_to_links_epollfd, EPOLL_CTL_ADD, knet_h->sockfd, &ev) != 0) goto exit_fail6; if (pthread_create(&knet_h->tap_to_links_thread, 0, _handle_tap_to_links_thread, (void *) knet_h) != 0) goto exit_fail6; if (pthread_create(&knet_h->recv_from_links_thread, 0, _handle_recv_from_links_thread, (void *) knet_h) != 0) goto exit_fail7; if (pthread_create(&knet_h->heartbt_thread, 0, _handle_heartbt_thread, (void *) knet_h) != 0) goto exit_fail8; return knet_h; exit_fail8: pthread_cancel(knet_h->recv_from_links_thread); exit_fail7: pthread_cancel(knet_h->tap_to_links_thread); exit_fail6: if (knet_h->tap_to_links_epollfd >= 0) close(knet_h->tap_to_links_epollfd); if (knet_h->recv_from_links_epollfd >= 0) close(knet_h->recv_from_links_epollfd); pthread_rwlock_destroy(&knet_h->list_rwlock); exit_fail5: free(knet_h->pingbuf); exit_fail4: free(knet_h->recv_from_links_buf); exit_fail3: free(knet_h->tap_to_links_buf); exit_fail2: crypto_fini(knet_h); exit_fail1: free(knet_h); return NULL; } int knet_handle_free(knet_handle_t knet_h) { void *retval; if ((knet_h->host_head != NULL) || (knet_h->listener_head != NULL)) goto exit_busy; pthread_cancel(knet_h->heartbt_thread); pthread_join(knet_h->heartbt_thread, &retval); if (retval != PTHREAD_CANCELED) goto exit_busy; pthread_cancel(knet_h->tap_to_links_thread); pthread_join(knet_h->tap_to_links_thread, &retval); if (retval != PTHREAD_CANCELED) goto exit_busy; pthread_cancel(knet_h->recv_from_links_thread); pthread_join(knet_h->recv_from_links_thread, &retval); if (retval != PTHREAD_CANCELED) goto exit_busy; close(knet_h->tap_to_links_epollfd); close(knet_h->recv_from_links_epollfd); pthread_rwlock_destroy(&knet_h->list_rwlock); free(knet_h->tap_to_links_buf); free(knet_h->recv_from_links_buf); free(knet_h->pingbuf); crypto_fini(knet_h); free(knet_h); return 0; exit_busy: errno = EBUSY; return -EBUSY; } void knet_handle_setfwd(knet_handle_t knet_h, int enabled) { knet_h->enabled = (enabled == 1) ? 1 : 0; } void knet_link_timeout(struct knet_link *lnk, time_t interval, time_t timeout, int precision) { lnk->ping_interval = interval * 1000; /* microseconds */ lnk->pong_timeout = timeout * 1000; /* microseconds */ lnk->latency_fix = precision; lnk->latency_exp = precision - \ ((lnk->ping_interval * precision) / 8000000); } static void _handle_tap_to_links(knet_handle_t knet_h) { int j; - ssize_t len, snt; - size_t outlen; + ssize_t len, snt, outlen; struct knet_host *i; len = read(knet_h->sockfd, knet_h->tap_to_links_buf->kf_data, KNET_DATABUFSIZE - KNET_FRAME_SIZE); if (len == 0) { /* TODO: disconnection, should never happen! */ return; } len += KNET_FRAME_SIZE; if (knet_h->enabled != 1) /* data forward is disabled */ return; /* TODO: packet inspection */ if (pthread_rwlock_rdlock(&knet_h->list_rwlock) != 0) return; if (crypto_encrypt_and_sign(knet_h->crypto_instance, (const unsigned char *)knet_h->tap_to_links_buf, len, knet_h->tap_to_links_buf_crypt, &outlen) < 0) return; for (i = knet_h->host_head; i != NULL; i = i->next) { for (j = 0; j < KNET_MAX_LINK; j++) { if (i->link[j].enabled != 1) /* link is disabled */ continue; snt = sendto(i->link[j].sock, knet_h->tap_to_links_buf_crypt, outlen, MSG_DONTWAIT, (struct sockaddr *) &i->link[j].address, sizeof(struct sockaddr_storage)); if ((i->active == 0) && (snt == len)) break; } } pthread_rwlock_unlock(&knet_h->list_rwlock); } static void _handle_recv_from_links(knet_handle_t knet_h, int sockfd) { - ssize_t len; - size_t outlen; + ssize_t len, outlen; struct sockaddr_storage address; socklen_t addrlen; struct knet_host *src_host; struct knet_link *src_link; unsigned long long latency_last; if (pthread_rwlock_rdlock(&knet_h->list_rwlock) != 0) return; addrlen = sizeof(struct sockaddr_storage); len = recvfrom(sockfd, knet_h->recv_from_links_buf, KNET_DATABUFSIZE, MSG_DONTWAIT, (struct sockaddr *) &address, &addrlen); if (crypto_authenticate_and_decrypt(knet_h->crypto_instance, (unsigned char *)knet_h->recv_from_links_buf, &len) < 0) goto exit_unlock; if (len < (KNET_FRAME_SIZE + 1)) goto exit_unlock; if (ntohl(knet_h->recv_from_links_buf->kf_magic) != KNET_FRAME_MAGIC) goto exit_unlock; if (knet_h->recv_from_links_buf->kf_version != KNET_FRAME_VERSION) goto exit_unlock; src_host = NULL; src_link = NULL; if ((knet_h->recv_from_links_buf->kf_type & KNET_FRAME_PMSK) != 0) { knet_h->recv_from_links_buf->kf_node = ntohs(knet_h->recv_from_links_buf->kf_node); src_host = knet_h->host_index[knet_h->recv_from_links_buf->kf_node]; if (src_host == NULL) /* host not found */ goto exit_unlock; src_link = src_host->link + (knet_h->recv_from_links_buf->kf_link % KNET_MAX_LINK); } switch (knet_h->recv_from_links_buf->kf_type) { case KNET_FRAME_DATA: if (knet_h->enabled != 1) /* data forward is disabled */ break; write(knet_h->sockfd, knet_h->recv_from_links_buf->kf_data, len - KNET_FRAME_SIZE); break; case KNET_FRAME_PING: knet_h->recv_from_links_buf->kf_type = KNET_FRAME_PONG; knet_h->recv_from_links_buf->kf_node = htons(knet_h->node_id); if (crypto_encrypt_and_sign(knet_h->crypto_instance, (const unsigned char *)knet_h->recv_from_links_buf, len, knet_h->recv_from_links_buf_crypt, &outlen) < 0) break; sendto(src_link->sock, knet_h->recv_from_links_buf_crypt, outlen, MSG_DONTWAIT, (struct sockaddr *) &src_link->address, sizeof(struct sockaddr_storage)); break; case KNET_FRAME_PONG: clock_gettime(CLOCK_MONOTONIC, &src_link->pong_last); timespec_diff(knet_h->recv_from_links_buf->kf_time, src_link->pong_last, &latency_last); src_link->latency = ((src_link->latency * src_link->latency_exp) + ((latency_last / 1000llu) * (src_link->latency_fix - src_link->latency_exp))) / src_link->latency_fix; if (src_link->latency < src_link->pong_timeout) src_link->enabled = 1; break; default: goto exit_unlock; } exit_unlock: pthread_rwlock_unlock(&knet_h->list_rwlock); } static void _handle_check_each(knet_handle_t knet_h, struct knet_link *dst_link) { int len; - size_t outlen; + ssize_t outlen; struct timespec clock_now, pong_last; unsigned long long diff_ping; /* caching last pong to avoid race conditions */ pong_last = dst_link->pong_last; if (clock_gettime(CLOCK_MONOTONIC, &clock_now) != 0) return; timespec_diff(dst_link->ping_last, clock_now, &diff_ping); if (diff_ping >= (dst_link->ping_interval * 1000llu)) { knet_h->pingbuf->kf_time = clock_now; knet_h->pingbuf->kf_link = dst_link->link_id; if (crypto_encrypt_and_sign(knet_h->crypto_instance, (const unsigned char *)knet_h->pingbuf, KNET_PINGBUFSIZE, knet_h->pingbuf_crypt, &outlen) < 0) return; len = sendto(dst_link->sock, knet_h->pingbuf_crypt, outlen, MSG_DONTWAIT, (struct sockaddr *) &dst_link->address, sizeof(struct sockaddr_storage)); if (len == outlen) dst_link->ping_last = clock_now; } if (dst_link->enabled == 1) { timespec_diff(pong_last, clock_now, &diff_ping); if (diff_ping >= (dst_link->pong_timeout * 1000llu)) dst_link->enabled = 0; /* TODO: might need write lock */ } } static void *_handle_heartbt_thread(void *data) { int j; knet_handle_t knet_h; struct knet_host *i; knet_h = (knet_handle_t) data; /* preparing ping buffer */ knet_h->pingbuf->kf_magic = htonl(KNET_FRAME_MAGIC); knet_h->pingbuf->kf_version = KNET_FRAME_VERSION; knet_h->pingbuf->kf_type = KNET_FRAME_PING; knet_h->pingbuf->kf_node = htons(knet_h->node_id); while (1) { usleep(KNET_PING_TIMERES); if (pthread_rwlock_rdlock(&knet_h->list_rwlock) != 0) continue; for (i = knet_h->host_head; i != NULL; i = i->next) { for (j = 0; j < KNET_MAX_LINK; j++) { if (i->link[j].ready != 1) continue; _handle_check_each(knet_h, &i->link[j]); } } pthread_rwlock_unlock(&knet_h->list_rwlock); } return NULL; } static void *_handle_tap_to_links_thread(void *data) { knet_handle_t knet_h; struct epoll_event events[KNET_MAX_EVENTS]; knet_h = (knet_handle_t) data; /* preparing data buffer */ knet_h->tap_to_links_buf->kf_magic = htonl(KNET_FRAME_MAGIC); knet_h->tap_to_links_buf->kf_version = KNET_FRAME_VERSION; knet_h->tap_to_links_buf->kf_type = KNET_FRAME_DATA; while (1) { if (epoll_wait(knet_h->tap_to_links_epollfd, events, KNET_MAX_EVENTS, -1) >= 1) _handle_tap_to_links(knet_h); } return NULL; } static void *_handle_recv_from_links_thread(void *data) { int i, nev; knet_handle_t knet_h; struct epoll_event events[KNET_MAX_EVENTS]; knet_h = (knet_handle_t) data; /* preparing data buffer */ knet_h->recv_from_links_buf->kf_magic = htonl(KNET_FRAME_MAGIC); knet_h->recv_from_links_buf->kf_version = KNET_FRAME_VERSION; while (1) { nev = epoll_wait(knet_h->recv_from_links_epollfd, events, KNET_MAX_EVENTS, -1); for (i = 0; i < nev; i++) { _handle_recv_from_links(knet_h, events[i].data.fd); } } return NULL; } diff --git a/libknet/nsscrypto.c b/libknet/nsscrypto.c index 4cf12833..40095ec8 100644 --- a/libknet/nsscrypto.c +++ b/libknet/nsscrypto.c @@ -1,599 +1,599 @@ #include "config.h" #include #include #include #include #include #include #include "nsscrypto.h" #include "libknet-private.h" #ifdef CRYPTO_DEBUG #define log_printf(format, args...) fprintf(stderr, format "\n", ##args); #else #define log_printf(format, args...); #endif /* * crypto definitions and conversion tables */ #define SALT_SIZE 16 #define KNET_DATABUFSIZE_CRYPT KNET_DATABUFSIZE * 2 enum crypto_crypt_t { CRYPTO_CIPHER_TYPE_NONE = 0, CRYPTO_CIPHER_TYPE_AES256 = 1 }; CK_MECHANISM_TYPE cipher_to_nss[] = { 0, /* CRYPTO_CIPHER_TYPE_NONE */ CKM_AES_CBC_PAD /* CRYPTO_CIPHER_TYPE_AES256 */ }; size_t cipher_key_len[] = { 0, /* CRYPTO_CIPHER_TYPE_NONE */ 32, /* CRYPTO_CIPHER_TYPE_AES256 */ }; size_t cypher_block_len[] = { 0, /* CRYPTO_CIPHER_TYPE_NONE */ AES_BLOCK_SIZE /* CRYPTO_CIPHER_TYPE_AES256 */ }; /* * hash definitions and conversion tables */ enum crypto_hash_t { CRYPTO_HASH_TYPE_NONE = 0, CRYPTO_HASH_TYPE_MD5 = 1, CRYPTO_HASH_TYPE_SHA1 = 2, CRYPTO_HASH_TYPE_SHA256 = 3, CRYPTO_HASH_TYPE_SHA384 = 4, CRYPTO_HASH_TYPE_SHA512 = 5 }; CK_MECHANISM_TYPE hash_to_nss[] = { 0, /* CRYPTO_HASH_TYPE_NONE */ CKM_MD5_HMAC, /* CRYPTO_HASH_TYPE_MD5 */ CKM_SHA_1_HMAC, /* CRYPTO_HASH_TYPE_SHA1 */ CKM_SHA256_HMAC, /* CRYPTO_HASH_TYPE_SHA256 */ CKM_SHA384_HMAC, /* CRYPTO_HASH_TYPE_SHA384 */ CKM_SHA512_HMAC /* CRYPTO_HASH_TYPE_SHA512 */ }; size_t hash_len[] = { 0, /* CRYPTO_HASH_TYPE_NONE */ MD5_LENGTH, /* CRYPTO_HASH_TYPE_MD5 */ SHA1_LENGTH, /* CRYPTO_HASH_TYPE_SHA1 */ SHA256_LENGTH, /* CRYPTO_HASH_TYPE_SHA256 */ SHA384_LENGTH, /* CRYPTO_HASH_TYPE_SHA384 */ SHA512_LENGTH /* CRYPTO_HASH_TYPE_SHA512 */ }; size_t hash_block_len[] = { 0, /* CRYPTO_HASH_TYPE_NONE */ MD5_BLOCK_LENGTH, /* CRYPTO_HASH_TYPE_MD5 */ SHA1_BLOCK_LENGTH, /* CRYPTO_HASH_TYPE_SHA1 */ SHA256_BLOCK_LENGTH, /* CRYPTO_HASH_TYPE_SHA256 */ SHA384_BLOCK_LENGTH, /* CRYPTO_HASH_TYPE_SHA384 */ SHA512_BLOCK_LENGTH /* CRYPTO_HASH_TYPE_SHA512 */ }; struct crypto_instance { PK11SymKey *nss_sym_key; PK11SymKey *nss_sym_key_sign; unsigned char *private_key; unsigned int private_key_len; int crypto_cipher_type; int crypto_hash_type; }; /* * crypt/decrypt functions */ static int string_to_crypto_cipher_type(const char* crypto_cipher_type) { if (strcmp(crypto_cipher_type, "none") == 0) { return CRYPTO_CIPHER_TYPE_NONE; } else if (strcmp(crypto_cipher_type, "aes256") == 0) { return CRYPTO_CIPHER_TYPE_AES256; } return -1; } static int init_nss_crypto(struct crypto_instance *instance) { PK11SlotInfo* crypt_slot = NULL; SECItem crypt_param; if (!cipher_to_nss[instance->crypto_cipher_type]) { return 0; } crypt_param.type = siBuffer; crypt_param.data = instance->private_key; crypt_param.len = cipher_key_len[instance->crypto_cipher_type]; crypt_slot = PK11_GetBestSlot(cipher_to_nss[instance->crypto_cipher_type], NULL); if (crypt_slot == NULL) { log_printf("Unable to find security slot (err %d)", PR_GetError()); return -1; } instance->nss_sym_key = PK11_ImportSymKey(crypt_slot, cipher_to_nss[instance->crypto_cipher_type], PK11_OriginUnwrap, CKA_ENCRYPT|CKA_DECRYPT, &crypt_param, NULL); if (instance->nss_sym_key == NULL) { log_printf("Failure to import key into NSS (err %d)", PR_GetError()); return -1; } PK11_FreeSlot(crypt_slot); return 0; } static int encrypt_nss( struct crypto_instance *instance, const unsigned char *buf_in, - const size_t buf_in_len, + const ssize_t buf_in_len, unsigned char *buf_out, - size_t *buf_out_len) + ssize_t *buf_out_len) { PK11Context* crypt_context = NULL; SECItem crypt_param; SECItem *nss_sec_param = NULL; int tmp1_outlen = 0; unsigned int tmp2_outlen = 0; unsigned char *salt = buf_out; unsigned char *data = buf_out + SALT_SIZE; int err = -1; if (PK11_GenerateRandom (salt, SALT_SIZE) != SECSuccess) { log_printf("Failure to generate a random number %d", PR_GetError()); goto out; } crypt_param.type = siBuffer; crypt_param.data = salt; crypt_param.len = SALT_SIZE; nss_sec_param = PK11_ParamFromIV (cipher_to_nss[instance->crypto_cipher_type], &crypt_param); if (nss_sec_param == NULL) { log_printf("Failure to set up PKCS11 param (err %d)", PR_GetError()); goto out; } /* * Create cipher context for encryption */ crypt_context = PK11_CreateContextBySymKey (cipher_to_nss[instance->crypto_cipher_type], CKA_ENCRYPT, instance->nss_sym_key, nss_sec_param); if (!crypt_context) { log_printf("PK11_CreateContext failed (encrypt) crypt_type=%d (err %d)", (int)cipher_to_nss[instance->crypto_cipher_type], PR_GetError()); goto out; } if (PK11_CipherOp(crypt_context, data, &tmp1_outlen, KNET_DATABUFSIZE_CRYPT, (unsigned char *)buf_in, buf_in_len) != SECSuccess) { log_printf("PK11_CipherOp failed (encrypt) crypt_type=%d (err %d)", (int)cipher_to_nss[instance->crypto_cipher_type], PR_GetError()); goto out; } if (PK11_DigestFinal(crypt_context, data + tmp1_outlen, &tmp2_outlen, KNET_DATABUFSIZE_CRYPT - tmp1_outlen) != SECSuccess) { log_printf("PK11_DigestFinal failed (encrypt) crypt_type=%d (err %d)", (int)cipher_to_nss[instance->crypto_cipher_type], PR_GetError()); goto out; } *buf_out_len = tmp1_outlen + tmp2_outlen + SALT_SIZE; err = 0; out: if (crypt_context) { PK11_DestroyContext(crypt_context, PR_TRUE); } if (nss_sec_param) { SECITEM_FreeItem(nss_sec_param, PR_TRUE); } return err; } static int decrypt_nss ( struct crypto_instance *instance, unsigned char *buf, - int *buf_len) + ssize_t *buf_len) { PK11Context* decrypt_context = NULL; SECItem decrypt_param; int tmp1_outlen = 0; unsigned int tmp2_outlen = 0; unsigned char *salt = buf; unsigned char *data = salt + SALT_SIZE; int datalen = *buf_len - SALT_SIZE; unsigned char outbuf[KNET_DATABUFSIZE_CRYPT]; int outbuf_len; int err = -1; /* Create cipher context for decryption */ decrypt_param.type = siBuffer; decrypt_param.data = salt; decrypt_param.len = SALT_SIZE; decrypt_context = PK11_CreateContextBySymKey(cipher_to_nss[instance->crypto_cipher_type], CKA_DECRYPT, instance->nss_sym_key, &decrypt_param); if (!decrypt_context) { log_printf("PK11_CreateContext (decrypt) failed (err %d)", PR_GetError()); goto out; } if (PK11_CipherOp(decrypt_context, outbuf, &tmp1_outlen, sizeof(outbuf), data, datalen) != SECSuccess) { log_printf("PK11_CipherOp (decrypt) failed (err %d)", PR_GetError()); goto out; } if (PK11_DigestFinal(decrypt_context, outbuf + tmp1_outlen, &tmp2_outlen, sizeof(outbuf) - tmp1_outlen) != SECSuccess) { log_printf("PK11_DigestFinal (decrypt) failed (err %d)", PR_GetError()); goto out; } outbuf_len = tmp1_outlen + tmp2_outlen; memset(buf, 0, *buf_len); memcpy(buf, outbuf, outbuf_len); *buf_len = outbuf_len; err = 0; out: if (decrypt_context) { PK11_DestroyContext(decrypt_context, PR_TRUE); } return err; } /* * hash/hmac/digest functions */ static int string_to_crypto_hash_type(const char* crypto_hash_type) { if (strcmp(crypto_hash_type, "none") == 0) { return CRYPTO_HASH_TYPE_NONE; } else if (strcmp(crypto_hash_type, "md5") == 0) { return CRYPTO_HASH_TYPE_MD5; } else if (strcmp(crypto_hash_type, "sha1") == 0) { return CRYPTO_HASH_TYPE_SHA1; } else if (strcmp(crypto_hash_type, "sha256") == 0) { return CRYPTO_HASH_TYPE_SHA256; } else if (strcmp(crypto_hash_type, "sha384") == 0) { return CRYPTO_HASH_TYPE_SHA384; } else if (strcmp(crypto_hash_type, "sha512") == 0) { return CRYPTO_HASH_TYPE_SHA512; } return -1; } static int init_nss_hash(struct crypto_instance *instance) { PK11SlotInfo* hash_slot = NULL; SECItem hash_param; if (!hash_to_nss[instance->crypto_hash_type]) { return 0; } hash_param.type = siBuffer; hash_param.data = 0; hash_param.len = 0; hash_slot = PK11_GetBestSlot(hash_to_nss[instance->crypto_hash_type], NULL); if (hash_slot == NULL) { log_printf("Unable to find security slot (err %d)", PR_GetError()); return -1; } instance->nss_sym_key_sign = PK11_ImportSymKey(hash_slot, hash_to_nss[instance->crypto_hash_type], PK11_OriginUnwrap, CKA_SIGN, &hash_param, NULL); if (instance->nss_sym_key_sign == NULL) { log_printf("Failure to import key into NSS (err %d)", PR_GetError()); return -1; } PK11_FreeSlot(hash_slot); return 0; } static int calculate_nss_hash( struct crypto_instance *instance, const unsigned char *buf, const size_t buf_len, unsigned char *hash) { PK11Context* hash_context = NULL; SECItem hash_param; unsigned int hash_tmp_outlen = 0; unsigned char hash_block[hash_block_len[instance->crypto_hash_type]]; int err = -1; /* Now do the digest */ hash_param.type = siBuffer; hash_param.data = 0; hash_param.len = 0; hash_context = PK11_CreateContextBySymKey(hash_to_nss[instance->crypto_hash_type], CKA_SIGN, instance->nss_sym_key_sign, &hash_param); if (!hash_context) { log_printf("PK11_CreateContext failed (hash) hash_type=%d (err %d)", (int)hash_to_nss[instance->crypto_hash_type], PR_GetError()); goto out; } if (PK11_DigestBegin(hash_context) != SECSuccess) { log_printf("PK11_DigestBegin failed (hash) hash_type=%d (err %d)", (int)hash_to_nss[instance->crypto_hash_type], PR_GetError()); goto out; } if (PK11_DigestOp(hash_context, buf, buf_len) != SECSuccess) { log_printf("PK11_DigestOp failed (hash) hash_type=%d (err %d)", (int)hash_to_nss[instance->crypto_hash_type], PR_GetError()); goto out; } if (PK11_DigestFinal(hash_context, hash_block, &hash_tmp_outlen, hash_block_len[instance->crypto_hash_type]) != SECSuccess) { log_printf("PK11_DigestFinale failed (hash) hash_type=%d (err %d)", (int)hash_to_nss[instance->crypto_hash_type], PR_GetError()); goto out; } memcpy(hash, hash_block, hash_len[instance->crypto_hash_type]); err = 0; out: if (hash_context) { PK11_DestroyContext(hash_context, PR_TRUE); } return err; } /* * global/glue nss functions */ static int init_nss_db(struct crypto_instance *instance) { if ((!cipher_to_nss[instance->crypto_cipher_type]) && (!hash_to_nss[instance->crypto_hash_type])) { return 0; } if (NSS_NoDB_Init(".") != SECSuccess) { log_printf("NSS DB initialization failed (err %d)", PR_GetError()); return -1; } return 0; } static int init_nss(struct crypto_instance *instance) { if (init_nss_db(instance) < 0) { return -1; } if (init_nss_crypto(instance) < 0) { return -1; } if (init_nss_hash(instance) < 0) { return -1; } return 0; } /* * exported API */ int crypto_encrypt_and_sign ( struct crypto_instance *instance, const unsigned char *buf_in, - const size_t buf_in_len, + const ssize_t buf_in_len, unsigned char *buf_out, - size_t *buf_out_len) + ssize_t *buf_out_len) { if (cipher_to_nss[instance->crypto_cipher_type]) { if (encrypt_nss(instance, buf_in, buf_in_len, buf_out, buf_out_len) < 0) { return -1; } } else { memcpy(buf_out, buf_in, buf_in_len); *buf_out_len = buf_in_len; } if (hash_to_nss[instance->crypto_hash_type]) { if (calculate_nss_hash(instance, buf_out, *buf_out_len, buf_out + *buf_out_len) < 0) { return -1; } *buf_out_len = *buf_out_len + hash_len[instance->crypto_hash_type]; } return 0; } int crypto_authenticate_and_decrypt (struct crypto_instance *instance, unsigned char *buf, - int *buf_len) + ssize_t *buf_len) { if (hash_to_nss[instance->crypto_hash_type]) { unsigned char tmp_hash[hash_len[instance->crypto_hash_type]]; if (calculate_nss_hash(instance, buf, *buf_len - hash_len[instance->crypto_hash_type], tmp_hash) < 0) { return -1; } if (memcmp(tmp_hash, buf + (*buf_len - hash_len[instance->crypto_hash_type]), hash_len[instance->crypto_hash_type]) != 0) { log_printf("Digest does not match"); return -1; } *buf_len = *buf_len - hash_len[instance->crypto_hash_type]; } if (cipher_to_nss[instance->crypto_cipher_type]) { if (decrypt_nss(instance, buf, buf_len) < 0) { return -1; } } return 0; } int crypto_init( knet_handle_t knet_h, const struct knet_handle_cfg *knet_handle_cfg) { log_printf("Initizializing crypto module [%s/%s]", knet_handle_cfg->crypto_cipher_type, knet_handle_cfg->crypto_hash_type); knet_h->crypto_instance = malloc(sizeof(struct crypto_instance)); if (!knet_h->crypto_instance) { return -1; } memset(knet_h->crypto_instance, 0, sizeof(struct crypto_instance)); if (!knet_handle_cfg->crypto_cipher_type) { goto out_err; } knet_h->crypto_instance->crypto_cipher_type = string_to_crypto_cipher_type(knet_handle_cfg->crypto_cipher_type); if (knet_h->crypto_instance->crypto_cipher_type < 0) { goto out_err; } if (!knet_handle_cfg->crypto_hash_type) { goto out_err; } knet_h->crypto_instance->crypto_hash_type = string_to_crypto_hash_type(knet_handle_cfg->crypto_hash_type); if (knet_h->crypto_instance->crypto_hash_type < 0) { goto out_err; } knet_h->crypto_instance->private_key = knet_handle_cfg->private_key; knet_h->crypto_instance->private_key_len = knet_handle_cfg->private_key_len; if ((knet_h->crypto_instance->crypto_cipher_type > 0) || (knet_h->crypto_instance->crypto_hash_type > 0)) { if ((!knet_h->crypto_instance->private_key) || (knet_h->crypto_instance->private_key_len < 1024)) { goto out_err; } } knet_h->tap_to_links_buf_crypt = malloc(KNET_DATABUFSIZE_CRYPT); if (!knet_h->tap_to_links_buf_crypt) goto out_err; knet_h->pingbuf_crypt = malloc(KNET_DATABUFSIZE_CRYPT); if (!knet_h->pingbuf_crypt) goto out_err; knet_h->recv_from_links_buf_crypt = malloc(KNET_DATABUFSIZE_CRYPT); if (!knet_h->recv_from_links_buf_crypt) goto out_err; knet_h->crypto_instance->private_key = knet_handle_cfg->private_key; knet_h->crypto_instance->private_key_len = knet_handle_cfg->private_key_len; if (init_nss(knet_h->crypto_instance) < 0) { goto out_err; } return 0; out_err: crypto_fini(knet_h); return -1; } void crypto_fini( knet_handle_t knet_h) { if (knet_h->crypto_instance) { if (knet_h->crypto_instance->nss_sym_key) PK11_FreeSymKey(knet_h->crypto_instance->nss_sym_key); if (knet_h->crypto_instance->nss_sym_key_sign) PK11_FreeSymKey(knet_h->crypto_instance->nss_sym_key_sign); if (knet_h->pingbuf_crypt) free(knet_h->pingbuf_crypt); if (knet_h->tap_to_links_buf_crypt) free(knet_h->tap_to_links_buf_crypt); if (knet_h->recv_from_links_buf_crypt) free(knet_h->recv_from_links_buf_crypt); free(knet_h->crypto_instance); knet_h->crypto_instance = NULL; } return; } diff --git a/libknet/nsscrypto.h b/libknet/nsscrypto.h index 38cd5711..fa13fae5 100644 --- a/libknet/nsscrypto.h +++ b/libknet/nsscrypto.h @@ -1,28 +1,28 @@ #ifndef NSSCRYPTO_H_DEFINED #define NSSCRYPTO_H_DEFINED #include #include "libknet.h" struct crypto_instance; int crypto_authenticate_and_decrypt ( struct crypto_instance *instance, unsigned char *buf, - int *buf_len); + ssize_t *buf_len); int crypto_encrypt_and_sign ( struct crypto_instance *instance, const unsigned char *buf_in, - const size_t buf_in_len, + const ssize_t buf_in_len, unsigned char *buf_out, - size_t *buf_out_len); + ssize_t *buf_out_len); int crypto_init( knet_handle_t knet_h, const struct knet_handle_cfg *knet_handle_cfg); void crypto_fini( knet_handle_t knet_h); #endif /* NSSCRYPTO_H_DEFINED */