An Introduction to OpenSSL Programming, Part II of II
The basic problem we're facing is that SSL is a record-oriented protocol. Thus, even if we want to read only one byte from the SSL connection, we still need to read the entire record containing that byte into memory. Without the entire record in hand, OpenSSL can't check the record MAC, so we can't safely deliver the data to the programmer. Unfortunately, this behavior interacts poorly with select(), as shown in Figure 1.

Figure 1. Read Interaction with SSL
The left-hand side of Figure 1 shows the situation when the machine has received a record but it's still waiting in the network buffers. The arrow represents the read pointer that is set at the beginning of the buffer. The bottom row represents data decoded by OpenSSL but not yet read by the program (the SSL buffer). This buffer is currently empty so we haven't shown a box. If the program calls select() at this point, it will return immediately, indicating that a call to read() will succeed. Now, imagine that the programmer calls SSL_read() requesting one byte. This takes us to the situation at the right side of the figure.
As we said earlier, the OpenSSL has to read the entire record in order to deliver even a single byte to the program. In general, the application does not know the size of records, and so its reads will not match the records. Thus, the box in the upper right-hand corner shows that the read pointer has moved to the end of the record. We've read all the data in the network buffer. When the implementation decrypts and verifies the record, it places the data in the SSL buffer. Then it delivers the one byte that the program asked for in SSL_read(). We show the SSL buffer in the lower right-hand corner. The read pointer points somewhere in the buffer, indicating that some of the data is available for reading but some has already been read.
Consider what happens if the programmer calls select() at this point. select() is concerned solely with the contents of the network buffer, and that's empty. Thus, as far as select() is concerned there's no data to read. Depending on the exact arguments it's passed, it will either return and say that there's nothing to read or wait for some more network data to become available. In either case we wouldn't read the data in the SSL buffer. Note that if another record arrived, select() would indicate that the socket was ready to read and, we'd have an opportunity to read more data.
Thus, select() is an unreliable guide to whether there is SSL data ready to read. We need some way to determine the status of the SSL buffer. This can't be provided by the operating system because it has no access to the SSL buffers. It must be provided OpenSSL. OpenSSL provides exactly such a function. The function SSL_pending() tells us whether there is data in the SSL buffer for a given socket. Listing 8 shows SSL_pending() in action.
Listing 8. Reading Data Using SSL_Pending()
49 /* Now check if there's data to read */
50 if((FD_ISSET(sock,&readfds) && !write_blocked_on_read) ||
51 (read_blocked_on_write && FD_ISSET(sock,&writefds))){
52 do {
53 read_blocked_on_write=0;
54 read_blocked=0;
55
56 r=SSL_read(ssl,s2c,BUFSIZZ);
57
58 switch(SSL_get_error(ssl,r)){
59 case SSL_ERROR_NONE:
60 /* Note: this call could block, which blocks the
61 entire application. It's arguable this is the
62 right behavior since this is essentially a terminal
63 client. However, in some other applications you
64 would have to prevent this condition */
65 fwrite(s2c,1,r,stdout);
66 break;
67 case SSL_ERROR_ZERO_RETURN:
68 /* End of data */
69 if(!shutdown_wait)
70 SSL_shutdown(ssl);
71 goto end;
72 break;
73 case SSL_ERROR_WANT_READ:
74 read_blocked=1;
75 break;
76
77 /* We get a WANT_WRITE if we're
78 trying to rehandshake and we block on
79 a write during that rehandshake.
80
81 We need to wait on the socket to be
82 writeable but reinitiate the read
83 when it is */
84 case SSL_ERROR_WANT_WRITE:
85 read_blocked_on_write=1;
86 break;
87 default:
88 berr_exit("SSL read problem");
89 }
90
91 /* We need a check for read_blocked here because
92 SSL_pending() doesn't work properly during the
93 handshake. This check prevents a busy-wait
94 loop around SSL_read() */
95 } while (SSL_pending(ssl) && !read_blocked);
96 }
The logic of this code is fairly straightforward. select() has been called earlier, setting the variable readfds with the sockets that are ready to read. If the SSL socket is ready to read, we go ahead and try to fill our buffer, unless the variable write_blocked_on_read is set (this variable is used when we're rehandshaking and we'll discuss it later). Once we've read some data, we write it to the console. Then we check with SSL_pending() to see if the record was longer than our buffer. If it was, we loop back and read some more data.
Note that we've added a new branch to our switch statement: a check for SSL_ERROR_WANT_READ. What's going on here is that we've set the socket for nonblocking operation. Recall that we said that if you called read() when the network buffers were empty, it would simply block (wait) until they weren't. Setting the socket to nonblocking causes it to return immediately, saying that it would have blocked.
To understand why we've done this, consider what happens if an SSL record arrives in two pieces. When the first piece arrives, select() will signal that we're ready to read. However, we need to read the entire record in order to return any data, so this is a false positive. Attempting to read all that data will block, leading to exactly the deadlock we were trying to avoid. Instead, we set the socket to non-blocking and catch the error, which OpenSSL translates to SSL_ERROR_WANT_READ.
It's worth noting that the call to fwrite() that we use to write to the console can block. This will cause the entire application to stall. This is reasonable behavior in a terminal client--if the user isn't looking at the screen we want the server to wait for him--but in other applications we might have to make this file descriptor non-blocking and select() on it as well. This is left as an exercise for the reader.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Designing Electronics with Linux | May 22, 2013 |
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
- New Products
- Linux Systems Administrator
- Senior Perl Developer
- Technical Support Rep
- UX Designer
- Web & UI Developer (JavaScript & j Query)
- Designing Electronics with Linux
- Dynamic DNS—an Object Lesson in Problem Solving
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Using Salt Stack and Vagrant for Drupal Development
- Nice article, thanks for the
7 hours 1 min ago - I once had a better way I
12 hours 47 min ago - Not only you I too assumed
13 hours 4 min ago - another very interesting
14 hours 57 min ago - Reply to comment | Linux Journal
16 hours 51 min ago - Reply to comment | Linux Journal
23 hours 45 min ago - Reply to comment | Linux Journal
1 day 1 min ago - Favorite (and easily brute-forced) pw's
1 day 1 hour ago - Have you tried Boxen? It's a
1 day 7 hours ago - seo services in india
1 day 12 hours ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Featured Jobs
| Linux Systems Administrator | Houston and Austin, Texas | Host Gator |
| Senior Perl Developer | Austin, Texas | Host Gator |
| Technical Support Rep | Houston and Austin, Texas | Host Gator |
| UX Designer | Austin, Texas | Host Gator |
| Web & UI Developer (JavaScript & j Query) | Austin, Texas | Host Gator |
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?



Comments
Block socket with SSL_MODE_AUTO_RETRY
If I use block socket with SSL_MODE_AUTO_RETRY
The flag SSL_MODE_AUTO_RETRY will cause read/write operations to only return after the handshake and successful completion.
Do I have to handle the retrying in SSL_Read and SSL_Write? Isn't it easier to do this way? I know it hurts throughput a little, but is it a big deal?