Skip to content
This repository has been archived by the owner on Jun 27, 2019. It is now read-only.

Crypto & Sign #802

Closed
barbieri opened this issue Sep 29, 2015 · 5 comments
Closed

Crypto & Sign #802

barbieri opened this issue Sep 29, 2015 · 5 comments
Labels

Comments

@barbieri
Copy link

Soletta should provide cryptographic and sign functions to be used in multiple subsystems:

  • persistence nodes could save ciphered information such as passwords;
  • module, configuration and fbp could check the signature, avoiding to load malicious data (ie: when downloaded from the internet);
  • C programs could use those directly;
  • network modules could use TLS/SSL/DTLS.

Multiple backends should be supported, since different OS have different support libraries (ie: OpenSSL/GnuTLS on Linux, PolarSSL on MBed, etc).

NOTE: This is a macro-ticket. Split it into more fine grained tasks before implementing.

@barbieri barbieri added the task label Sep 29, 2015
@lpereira
Copy link
Contributor

For TLS/DTLS, OpenBSD's libtls API is quite simple; it's a wrapper around {Open/Libre/Boring}SSL, and could either be used directly, or serve as inspiration: http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/tls_accept_fds.3?query=tls_init&sec=3

@barbieri
Copy link
Author

Linux kernel seems to provide some of it to userspace, the benefit of not requiring an extra library and being hardware accelerated:

I just tried sha1sum on my PC and it uses openssl, strace says no socket is used... then I guess openssl is not ported to use that if available.

@barbieri
Copy link
Author

barbieri commented Oct 7, 2015

I did a test with kernel's crypto API AF_ALG socket and it's indeed simple to use. But the libkcapi is a blocking API that won't play nice with the main loop, granted our usage is not working with huge streaming blobs, but we should keep the API async anyway, given that other OS with hwaccel will all be async.

That said, before I go and write the src/lib/crypto subsystem for linux using its kernel crypto API, let's decide on the API. My proposal is:

// although they are all handled similarly in Linux, I'd keep encrypt/decrypt and hasher (digest) algorithms separated handlers
struct sol_crypto_hasher_config {
    const char *algorithm; /* use Linux names to start, such as md5, sha1, hmac(sha1), crc32... */
    struct sol_str_slice key; /* if len > 0, a key to be used in the hash algorithm */
    void (*on_hash_ready)(void *data, struct sol_crypto_hasher *hasher, const struct sol_blob *output); /* must be valid */
    void (*on_feed_done)(void *data, struct sol_crypto_hasher *hasher, struct sol_blob *input); /* may be NULL */
    const void *data;
};
struct sol_crypto_hasher *sol_crypto_hasher_new(const struct sol_crypto_hasher_config *cfg);
void sol_crypto_hasher_del(struct sol_crypto_hasher *hasher);
int sol_crypto_hasher_feed(struct sol_crypto_hasher *hasher, struct sol_blob *input, bool is_final);

Rationale:

  • algorithm as a string will allow us to be extensible and not rely on a huge enumeration. The algorithms that are supported are always platform dependent anyways. We could have a series of #define or SOL_API const char * with the common names such as md5, crc32 and sha1.
  • Data will be feed using struct sol_blob, this allows refcounting and customized free() of special data, as well as easy-to-management slice due parenting/nesting. Whole blobs are used since if user want to feed only a slice, then just create a child blob, it will keep API simple and uniform.
  • The hash is dispatched using on_hash_ready() once the last chunk is fed (is_final = true).

Opens:

  • What to do once a new feed happens after a is_final=true? Fail? Restart? Continue feeding as if it was not final?
  • If is_final = true means it's terminated, should the hasher be automatically deleted? Or users should call sol_crypto_hasher_del() from on_hash_ready()?

Implementation details:

  • On Linux we need to create a socket, then bind() and accept() a new socket to be used. Keys must be set on the socket we did bind(), not the one that was accept(), thus key affect all sockets accepted.
  • On Linux, to know the hash block and digest size we must use netlink and do a query.
  • Ideally we keep a vector of pending input blobs and offset (starts at 0). Then we register sol_fd_add() with SOL_FD_FLAGS_OUT and during each callback it will send() the block size to kernel, setting MSG_MORE if more chunks are expected. A more complex and performant operation is to use sendmsg() with an struct iovec filled with all queued blobs memory, then upon return we walk the list of blobs and update the offset, removing those where offset == blob->size (ie: done).
  • On deletion, all blobs are unreferenced and the socket is closed.

Comments? @ceolin, @lpereira, @ibriano, @cmarcelo

@barbieri
Copy link
Author

message digest was done using both linux kernel crypto api (kcapi) and openssl, already in master.

To do is encrypt/decrypt and transport layers such as ssl/tls/dtls.

@barbieri
Copy link
Author

closing, further work in #2009.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants