linuxopensslnph

Implementing SSL server using libssl and sendmsg() SCM_RIGHTS


I'm now wondering whether we can make some sort of SSL server based on the following policies/scheme under Linux environment.

(1) As for the initial request, it should be incoming in the parent server process. After establishing SSL connection and also handling initial parsing of the request, the request (socket) will be forwarded to a request-handling process to do further processing.

(2) The request-handling process will be something which should be running beforehand. We won't use any fork-exec-pipe based scheme here in this sense.

(3) As for the communication between the parent server process and the request handling process, some IPC has been established in order to copy opened socket descriptor from the parent server process to the request-handling process by using sendmsg() - SCM_RIGHTS technique.

(4) In terms of SSL functionality, we are supposed to use OpenSSL (libssl).

(5) In the request-handling process, we are supposed to create new SSL socket by making use of the shared socket descriptor from the parent server process.

The point is that I don't want to waste any performance of transferring data between the server and the request handling process. I don't want to spawn request handling process as per request basis, either. So I would like to spawn the request handling process in advance.

Although I'm not really sure whether what I'm trying make here is making sense to you, it would be appreciated if anyone of you could give me some hint on whether the above approach is feasible.


Solution

  • It is not clear what exactly you are looking for, especially where do you want to do the SSL encryption/decryption.

    Do you want to do the encryption/decryption inside the request handler processes?
    That seems the more likely interpretation. However you talk about doing some request parsing in the master process. Is the data parsed in the master process already a part of the SSL session? If so, you would have to do an SSL handshake (initialization and key exchange) in the master process in order to access the encrypted data. If you then passed the original socket to another process, it wouldn't have access to the SSL state of the parent process so it wouldn't be able to continue decrypting where the parent left off. If it tried to reinitialize SSL on the socket as if it were a clean connection, the client will probably (correctly) treat an unsolicited handshake in the middle of a connection as a protocol error and terminate the connection. If it didn't, it would present a security hole as it could be an attacker who maliciously redirected client's network traffic, instead of your request-handling process, who is forcing the re-initialization. It's generally not possible to pass initialized SSL sessions to different processes without also informing them of the complete internal state of OpenSSL (exchanged keys, some sequence numbers, etc.) along with this, which would be hard if not impossible.

    If you don't need to touch the SSL session in the parent process and you parse just some unencrypted data that come before the actual SSL session starts (analogous to e.g. the STARTTLS command in IMAP), your idea will work without problems. Just read what you need to, up to the point where the SSL exchange should start, then pass the socket to the backend process using SCM_RIGHTS (see e.g. the example in cmsg(3) or this site). There are also libraries that do the work for you, namely libancillary.

    Or do you expect the master process to do SSL encryption/decryption for the request handler processes?
    In that case it makes no sense to pass the original socket to the request-handler processes as the only thing they would get from it is encrypted data. In the scenario you have to open a new connection to the backend process as it will carry different data (decrypted). The master process will then read encrypted data from the network socket, decrypt it and write the result to the new socket for the request-handler. Analogically in the other direction.

    NB: If you just want your request handling processes not to worry about SSL at all, I'd recommend to let them listen on the loopback interface and use something like stud to do the SSL/TLS dirty work.

    In short, you have to choose one of the above. It's not possible to do both at the same time.