Using Linux crypto API from User Space for RSA - c

I am looking for a way to call Linux kernel crypto API from user space for RSA encryption/decryption. RSA function are implemented in linux kernel.
Currently, I found 2 way to call crypto API from user space:
AF_ALG socket, using [libkapi] (http://www.chronox.de/libkcapi.html). It seems to be the offical solution (https://www.kernel.org/doc/html/v4.19/crypto/userspace-if.html).
[cryptodev] (http://cryptodev-linux.org/) which uses ioctl.
Unfortunaly, cryptodev doesn't support asymmetric algorithms like RSA.
And I am not sur if AF_ALG supports akcipher like RSA. The result of cat /proc/crypto is:
...
name : rsa
driver : rsa-generic
module : kernel
priority : 100
refcnt : 1
selftest : passed
internal : no
type : akcipher
But, I tried to bind an AF_ALG socket with :
int sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
.salg_type = "akcipher",
.salg_name = "rsa"
};
The bind failed with ***ERROR : bind socket failed (2) : No such file or directory.
Did I miss something ? Is there an other way to call crypto API from user space ?

From the documentation:
The kernel crypto API is accessible from user space. Currently, the
following ciphers are accessible:
Message digest including keyed message digest (HMAC, CMAC)
Symmetric ciphers
AEAD ciphers
Random Number Generators
This means, that the akcipher cipher family is not available from userspace, hence binding to it fails with ENOENT. Indeed, checking with the linux kernel source reveals, that there is no algif_akcipher.c, where the userspace interface of the akcipher family would be implemented.

Related

Convert code using openssl to use mbedtls

I am trying to convert some C code written to run on a Mac to an embedded device that does not have any encryption libraries. The code for the Mac is using libcrypto. I tried building libcrypto from openssl sources for the embedded device but I get hundreds of errors due to function pointer prototypes not matching. openssl is riddled with huge macros. As an alternative I am now trying to use mbedtls but I have not been able to get a decrypt function to work.
The code I am trying to port is a bit odd. It has what it calls a public key and is actually calling RSA_public_encrypt() with no padding to decrypt data. As a test, I changed the Mac code to call RSA_public_decrypt() and it worked so I assume the key is symmetric. The key it is using looks like this:
"-----BEGIN PUBLIC KEY-----\n"
5 lines of Base64 strings
"-----END PUBLIC KEY-----\n"
For mbedtls I am using mbedtls_pk_parse_public_key() to parse the key. If I inspect the low level RSA key structure after parsing the key there is a 128 byte N component and a 16 byte E component. I get the same key data with both openssl and mbedtls so it appears that the key is parsed properly. When decrypting on the Mac with RSA_public_decrypt(), the input and output are both 128 bytes. For mbedtls, I am calling mbedtls_pk_decrypt() to decrypt but when I trace through the code it calls mbedtls_rsa_rsaes_pkcs1_v15_decrypt() which forces the padding to be 11 bytes.
So my questions are: 1) exactly what kind of "public" key contains only N and E components and uses no padding; 2) Am I calling the correct mbedtls decryption function?
EDIT: Tried another approach and my output buffer just gets filled with zeros.
mbedtls_rsa_context rsa;
mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
mbedtls_rsa_import_raw(&rsa, modulus, sizeof(modulus), NULL, 0, NULL, 0, NULL, 0, exp, sizeof(exp));
mbedtls_rsa_complete(&rsa);
mbedtls_rsa_public(&rsa, inBfr, outBfr);
mbedtls_rsa_free(&rsa);
EDIT 2: My ultimate target is an embedded device with an ARM processor but I was testing on Windows to see if mbedtls would work. I started with VS 2010 because that is what was being used for the project I am working on. I switched to VS 2015 and the 2nd approach of importing the raw key data and calling mbedtls_rsa_public() worked perfectly. I guess the VS 2010 compiler just isn't good enough. I then ported the code to the devlepment system for my embedded device and it also worked.
The equivalent of OpenSSL's RSA_public_encrypt(…, RSA_NO_PADDING) would be mbedtls_rsa_public. The function mbedtls_pk_encrypt only lets you access encryption mechanisms based on RSA (RSAES-PKCS1-v1_5 and RSAES-OAEP), not the raw RSA primitive (“textbook RSA” a.k.a. “RSA with no padding”).
You need to call mbedtls_pk_parse_public_key to parse the key, then get a pointer to the RSA key object with mbedtls_pk_rsa, and call mbedtls_rsa_public using this RSA key object.
mbedtls_pk_context pk;
mbedtls_pk_init(&pk);
mbedtls_rsa_context *rsa = mbedtls_pk_rsa(&pk);
mbedtls_rsa_public(&rsa, inBfr, outBfr);
mbedtls_pk_free(&pk);
I think this should work from your description, but obviously I can't test this without sample data.

Find Virtual Network Interfaces in C (Linux)

I try to find a way, in C code, to distinguish whether a network interface is virtual or physical.
I was thinking to check whether the network interface is mapped to a driver, assuming that if there is no driver, it is most likely a virtual adapter (is there a more relevant method?).
Example (on a physical adapter):
$ ethtool -i eth0
driver: e1000
....
Example (on a virtual adapter):
$ ethtool -i eth10
Cannot get driver information: Operation not supported
Naturally, I looked at the source of ethtool to understand how it accesses the driver info: https://github.com/torvalds/linux/blob/master/net/core/ethtool.c
Here's the part that interests us:
static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
void __user *useraddr)
{
struct ethtool_drvinfo info;
const struct ethtool_ops *ops = dev->ethtool_ops;
memset(&info, 0, sizeof(info));
info.cmd = ETHTOOL_GDRVINFO;
if (ops->get_drvinfo) {
ops->get_drvinfo(dev, &info);
} else if (dev->dev.parent && dev->dev.parent->driver) {
strlcpy(info.bus_info, dev_name(dev->dev.parent),
sizeof(info.bus_info));
strlcpy(info.driver, dev->dev.parent->driver->name,
sizeof(info.driver));
} else {
return -EOPNOTSUPP;
}
...
}
To get the net_device, there is a call to __dev_get_by_name(net, ifr->ifr_name), this function is apparently defined in
Problem is that __dev_get_by_name() and the required structures are defined in kernel files which I am not sure I can access from an external program.
Besides when I try to include headers such as , I get tons of redefinition of structures already defined in ...
I was wondering if there is a better way to get the driver info having a ifreq structure (http://man7.org/linux/man-pages/man7/netdevice.7.html).
ifreq structure is mostly a compatibility thing, as the new API in Linux is rtnetlink, but I do not recommend exploring it, unless you really have to. The ip shell utility gives access to more or less the entire stable part of the API, but I do not think it can show you the hardware device that is responsible for the device.
But:
I would have checked /sys/class/net/DEVICE_NAME/device symlink (is it present?)

Autonomically sending a message from kernel-module to user-space application without relying on the invoke of input. from user-space

I will give a detailed exp of the program and lead to the issue regarding the use of netlink socket communication.
The last paragraph asks the actual question I need an answer for, so you might wanna start by peeking it first.
Disclaimer before I start:
- I have made an earlier search before asking here and did not find complete solution / alternative to my issue.
- I know how to initialize a module and insert it to kernel.
- I know to handle communication between module and user-space without using netlink sockets. Meaning using struct file_operations func pointers assignments to later be invoked by the module program whenever a user attempts to read/write etc. and answer to the user using copy_to_user / copy_from_user.
- This topic refers to Linux OS, Mint 17 dist.
- Language is C
Okay, so I am building a system with 3 components:
1. user.c : user application (user types commands here)
2. storage.c : storage device ('virtual' disk-on-key)
3. device.ko : kernel module (used as proxy between 1. and 2.)
The purpose of this system is to be able (as a user) to:
- Copy files to the virtual disk-on-key device (2) - like an "upload" from local directory that belongs to the user.
- Save files from the virtual device on local directory - like "download" from the device storage to the user directory.
Design:
Assuming programs (1),(2) are compiled and running + (3) has successfully inserted using the bash command ' sudo insmod device.ko ' , the following should work like this (simulation ofc):
Step 1 (in user.c) -> user types 'download file.txt'
Step 2 (in device.ko) -> the device recognizes the user have tried to 'write' to it (actually user just passing the string "download file.txt") and invokes the 'write' implementation of the method we set on struct file_operation earlier on module_init().
The device (kernel module) now passes the data (string with a command) to the storage.c application, expecting an answer to later be retrieved to the user.c application.
Step 3 (in storage.c) -> now, lets say this program performs a busy-wait loop of 'readmsg()' and that's how a request from module event is triggered and recognized, the storage device now recognizes that the module has sent a request (string with a command \ data). Now, the storage programs shall perform an implementation of some function 'X' to send the data requested using sendmsg() somewhere inside the function.
Now, here comes the issue.
Usually, on all of the examples I've looked on web, the communication between the kernel-module and a user-space (or the storage.c program in our case) using netlink is triggered by the user-space and not vice versa. Meaning that the sendmsg() function from the user-space invokes the 'request(struct sk_buff *skb)' method (which is set on the module_init() part as following:
struct netlink_kernel_cfg cfg = {
.input = request // when storage.c sends something, it invokes the request function
};
so when the storage.c performs something like:
sendmsg(sock_fd,&msg,0); // send a msg to the module
the module invokes and runs the:
static void request(struct sk_buff *skb) {
char *msg ="Hello from kernel";
msg_size=strlen(msg);
netlink_holder=(struct nlmsghdr*)skb->data;
printk(KERN_INFO "Netlink received msg payload:%s\n",(char*)nlmsg_data(netlink_holder));
pid = netlink_holder->nlmsg_pid; // pid of sending process
skb_out = nlmsg_new(msg_size,0);
if(!skb_out){
printk(KERN_ERR "Failed to allocate new skb\n");
return;
}
netlink_holder=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0); // add a new netlink message to an skb. more info: http://elixir.free-electrons.com/linux/v3.2/source/include/net/netlink.h#L491
NETLINK_CB(skb_out).dst_group = 0; // not in multicast group
strncpy(nlmsg_data(netlink_holder),msg,msg_size); // assign data as char* (variable msg)
result=nlmsg_unicast(sock_netlink,skb_out,pid); // send data to storage. more info: http://elixir.free-electrons.com/linux/latest/source/include/net/netlink.h#L598
if(result<0)
printk(KERN_INFO "Error while sending bak to user\n");
}
and from all that big chunk, the only thing that im interesting in is actually doing this:
result=nlmsg_unicast(sock_netlink,skb_out,pid); // send data to storage.
BUT I can't use nlmsg_unicast() without having the strcut sk_buff* which is provided automatically for me whenever there's an invoke from storage.c !
To sum up everything:
How do I send a msg from the device.ko (kernel module) to the user-space withtout having to wait for request to invoke / rely on the provided strcut sk_buff parameter from the earlier shown 'request()' method ?
Hope this sums up the point.
Thanks.
The only question here is that you need the user-space program connected to kernel-space first to get the pid of your user-program.
After get the pid, you can manually construct the skb_out and send it out through netlink_unicast or nlmsg_unicast.
The pid is always needed, you can set it as static and let your user-space program connect to your device.ko to make a long-maintained link.
Although this question is asked at 2017, I believe OP has already found the answer :D

Serving multiple domains in one box with SNI

I'm using OpenSSL 0.9.8q in FreeBSD-8.2. I have 3 virtual hosts on my system and want to implement SNI to serve for all 3 of them in one server.
I have 3 separate certificates one for each, and in my ssl-server code I have to somehow find out what is the domain-name of client's request, and use the appropriate certificate file based on that. For this I wrote a function named get_ssl_servername_cb and passed it as callback function to SSL_CTX_set_tlsext_servername_callback. This way, in callback function I can get the the domain-name of the client's request.
But my problem is, this callback function is being executed after execution of SSL_accept function, but I have to choose and use the appropriate certificate before using SSL_new command, which is way before execution of SSL_accept.
So my question is, how can I use SSL_CTX_set_tlsext_servername_callback function for SNI?
but my problem is, this callback function is being executed after execution of "SSL_accept" function, but I have to choose and use the appropriate certificate before using "SSL_new" command, which is way before execution of SSL_accept.
When you start your server, you provide a default SSL_CTX. This is used for non-SNI clients, like SSLv3 clients and TLS clients that don't utilize SNI (like Windows XP). This is needed because the callback is not invoked in this situation.
Here are some examples to tickle the behavior using OpenSSL's s_client. To simulate a non-SNI client so that your get_ssl_servername_cb is not called, issue:
openssl s_client -connect localhost:8443 -ssl3 # SNI added at TLSv1
openssl s_client -connect localhost:8443 -tls1 # Windows XP client
To simulate a SNI client so that your get_ssl_servername_cb is called, issue:
openssl s_client -connect localhost:8443 -tls1 -servername localhost
You can also avoid the certificate verification errors by adding -CAfile. This is from one of my test scripts (for testing DSS/DSA certificates on localhost):
printf "GET / HTTP/1.1\r\n\r\n" | /usr/local/ssl/bin/openssl s_client \
-connect localhost:8443 -tls1 -servername localhost \
-CAfile pki/signing-dss-cert.pem
so my question is, how can I use "SSL_CTX_set_tlsext_servername_callback" function for SNI?
See the OpenSSL source code at <openssl dir>/apps/s_server.c; or see How to implement Server Name Indication(SNI) on OpenSSL in C or C++?.
In your get_ssl_servername_cb (set with SSL_CTX_set_tlsext_servername_callback), you examine the server name. One of two situations occur: you already have a SSL_CTX for the server's name, or you need to create a SSL_CTX for server's name.
Once you fetch the SSL_CTX from cache or create a new SSL_CTX, you then use SSL_set_SSL_CTX to swap in the context. There's an example of swapping in the new context in the OpenSSL source files. See the code for s_server.c (in <openssl dir>/apps/s_server.c). Follow the trail of ctx2,
Here's what it looks like in one of my projects. IsDomainInDefaultCert determines if the requested server name is provided by the default server certificate. If not, GetServerContext fetches the needed SSL_CTX. GetServerContext pulls the needed certificate out of an app-level cache; or creates it and puts it in the app-level cache (GetServerContext also asserts one reference count on the SSL_CTX so the OpenSSL library does not delete it from under the app).
static int ServerNameCallback(SSL *ssl, int *ad, void *arg)
{
UNUSED(ad);
UNUSED(arg);
ASSERT(ssl);
if (ssl == NULL)
return SSL_TLSEXT_ERR_NOACK;
const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
ASSERT(servername && servername[0]);
if (!servername || servername[0] == '\0')
return SSL_TLSEXT_ERR_NOACK;
/* Does the default cert already handle this domain? */
if (IsDomainInDefCert(servername))
return SSL_TLSEXT_ERR_OK;
/* Need a new certificate for this domain */
SSL_CTX* ctx = GetServerContext(servername);
ASSERT(ctx != NULL);
if (ctx == NULL)
return SSL_TLSEXT_ERR_NOACK;
/* Useless return value */
SSL_CTX* v = SSL_set_SSL_CTX(ssl, ctx);
ASSERT(v == ctx);
if (v != ctx)
return SSL_TLSEXT_ERR_NOACK;
return SSL_TLSEXT_ERR_OK;
}
In the code above, ad and arg are unused parameters. I don't know what ad does because I don't use it. arg can be used to pass in a context to the callback. I don't use arg either, but s_server.c uses it to print some debug information (the arg is a pointer to a BIOs tied to stderr (and a few others), IIRC).
For completeness, SSL_CTX are reference counted and they can be re-used. A newly created SSL_CTX has a count of 1, which is delegated to the OpenSSL internal caching mechanism. When you hand the SSL_CTX to a SSL object, the count increments to 2. When the SSL object calls SSL_CTX_free on the SSL_CTX, the function will decrement the reference count. If the context is expired and the reference count is 1, then the OpenSSL library will delete it from its internal cache.

Peer to Peer linux authentication in C

I have two embedded systems running Angstrom Linux that are connected via a Ethernet cross-over cable. I'm developing a C program that will allow the two systems to communicate with each other.
When the two computers talk to each other they first need to verify the identity of the other and encrypt the connection. I'm trying to use openssl to accomplish the authentication and encryption but I'm not totally sure what to do.
All the peer to peer questions are related to other languages or aren't related to openssl.
I’ve been trying to modify the code from An Introduction to OpenSSL Programming http://www.linuxjournal.com/article/4822 to get my embedded systems working, but haven’t been successful. The in the SSL_CTX *initialize_ctx which is in common.c and also load_dh_params(ctx,file) in server.c seem to be the problem areas. Here is my code for common.c with some of my modifications.
SSL_CTX *initialize_ctx(keyfile,password)
char *keyfile;
char *password;
{
SSL_METHOD *meth;
SSL_CTX *ctx;
char buffer[200];
if (!bio_err)
{
/* Global system initialization*/
SSL_library_init();
SSL_load_error_strings();
/* An error write context */
bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
}
debuglocation(__LINE__,__FILE__);
/* Set up a SIGPIPE handler */
signal(SIGPIPE,sigpipe_handle);
/* Create our context*/
meth=SSLv23_method();
ctx=SSL_CTX_new(meth);
debuglocation(__LINE__,__FILE__);
/* Load our keys and certificates*/
// if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile)))
// berr_exit("Can't read certificate file");
debuglocation(__LINE__,__FILE__);
pass=password;
/* TODO need to put a password on the key*/
//SSL_CTX_set_default_passwd_cb(ctx,password_cb);
//if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM)))
//http://www.openssl.org/docs/ssl/SSL_CTX_use_certificate.html#NOTES
if(!(SSL_CTX_use_RSAPrivateKey_file(ctx,"private.pem", SSL_FILETYPE_PEM)))
berr_exit("Can't read priveate rsa");
debuglocation(__LINE__,__FILE__);
//berr_exit("Can't read key file");
// /* Load the CAs we trust*/
// if (!(SSL_CTX_load_verify_locations(ctx,
// CA_LIST,0)))
// berr_exit("Can't read CA list");
#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
SSL_CTX_set_verify_depth(ctx,1);
#endif
return ctx;
}
And here is the server.c
void load_dh_params(ctx,file)
SSL_CTX *ctx;
char *file;
{
DH *ret=0;
BIO *bio;
//http://www.openssl.org/docs/crypto/BIO_s_file.html
// opens a file just like fopen with the second parameter as the type of open. Here it is read 'r'.
if ((bio=BIO_new_file(file,"r")) == NULL)
berr_exit("Couldn't open DH file");
//http://www.openssl.org/docs/crypto/pem.html
ret=PEM_read_bio_DHparams(bio,NULL,NULL,
NULL);
BIO_free(bio);
if(SSL_CTX_set_tmp_dh(ctx,ret)<0)
berr_exit("Couldn't set DH parameters");
}
My debuglocation function looks like this.
int debuglocation(int line, char * file)
{
static char c = 'A';
printf("Made it to line %d in %s call it %c\n",line,file, c);
c++;
return 0;
}
So when I run all that I get from the server.
2535:error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher:s3_srvr.c:1075:
And this from the client.
SSL connect error
2616:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:596:
Also I’m not sure what ssl commands to use to make the needed certificates.
It seemed like RSA would work well if both the embedded devices had one public and one priviate key, so I tried following http://www.devco.net/archives/2006/02/13/public_-_private_key_encryption_using_openssl.php
and made a script to make them for me.
openssl genrsa -out private.pem 1024
openssl rsa -in private.pem -out public.pem -outform PEM -pubout
Thanks in advance for the help. If you need more information please let me know. I think that answers to this question could be really helpful to anyone developing in C for an embedded system who needs some authentication.
Anthony
As the user that runs the comm process, do ssh_keygen.
Append the public part of the output, id_rsa.pub, to the ~/.ssh/authorized_keys on the other machine. Now you can run remote programs using ssh without logging in.
Edit. I suggested the above because of the hassle of working with certs. You need to have a trust store, correct directory permissions, etc. I think the first thing you're missing is loading the data on trusted certificates. See the link on how to do that. It's easier to check the authorization using the command line tools in openssl then to debug your program and get the SSL set up at the same time.
I ended up using ssh rather than trying to use openssl. It did make life much simpler. Maybe when I have more time I will figure it out the other way.

Resources