indented dtls tutorial

pull/1/head
lchristina26 2014-07-01 15:08:13 -06:00
parent 2629698168
commit 594248d9fd
1 changed files with 771 additions and 771 deletions

View File

@ -16,32 +16,32 @@ UDP header consists of 4 fields, each of which is 16 bits.
Field 1: Contains information about the port from which the message originated. Field 1: Contains information about the port from which the message originated.
Field 2: Contains information about the destination port. Field 2: Contains information about the destination port.
Field 3: Defines the length in bytes of the UDP header and data. Allows for datagram of Field 3: Defines the length in bytes of the UDP header and data. Allows for datagram of
maximum size 65,535 bytes to be defined. If larger, set to 0. (IPv6 will allow larger). maximum size 65,535 bytes to be defined. If larger, set to 0. (IPv6 will allow larger).
Field 4: Contains a Checksum for security purposes. Contains some checksum of the header and data. Field 4: Contains a Checksum for security purposes. Contains some checksum of the header and data.
CHECKSUM CHECKSUM
All 16 bit words are summed using “one's complement arithmetic”. The sum is then “one's complemented” and this is the value placed in the UDP checksum field. All 16 bit words are summed using “one's complement arithmetic”. The sum is then “one's complemented” and this is the value placed in the UDP checksum field.
Figure 1.1 Check Sum Example Figure 1.1 Check Sum Example
EXAMPLE: you have two 16 bit words as follows : EXAMPLE: you have two 16 bit words as follows :
ONE's COMPLEMENT OF WORD1: 1 0 0 1 1 1 1 0 0 1 1 0 0 0 1 0 ONE's COMPLEMENT OF WORD1: 1 0 0 1 1 1 1 0 0 1 1 0 0 0 1 0
ONE's COMPLEMENT OF WORD2: 0 1 0 1 0 0 0 1 0 1 0 0 1 1 0 1 ONE's COMPLEMENT OF WORD2: 0 1 0 1 0 0 0 1 0 1 0 0 1 1 0 1
--------------------------------- ---------------------------------
SUM: 1 1 1 0 1 1 1 1 1 0 1 0 1 1 1 1 SUM: 1 1 1 0 1 1 1 1 1 0 1 0 1 1 1 1
--------------------------------- ---------------------------------
ONE's COMPLEMENT OF SUM: 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 ONE's COMPLEMENT OF SUM: 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0
The final value would be placed in the Checksum Field. The final value would be placed in the Checksum Field.
1.2. Creating a UDP/IP Server 1.2. Creating a UDP/IP Server
There are five initial steps to creating a UDP/IP Server. There are five initial steps to creating a UDP/IP Server.
1. Create the socket 1. Create the socket
2. Identify the socket (IE give it a name) 2. Identify the socket (IE give it a name)
<Begin a loop> <Begin a loop>
3. On the server wait for a message 3. On the server wait for a message
4. Send a response to the client once message is received 4. Send a response to the client once message is received
@ -61,7 +61,7 @@ Field 3: Defines the length in bytes of the UDP header and data. Allows for data
The domain can also be referred to as the address family. It is the communication domain in which the socket should be created. Below you will see some of the examples domains or address families that we could work with. At the end will be a description of what we will choose specifically for a UDP server. The domain can also be referred to as the address family. It is the communication domain in which the socket should be created. Below you will see some of the examples domains or address families that we could work with. At the end will be a description of what we will choose specifically for a UDP server.
AF_INET: Internet Protocol (IP) AF_INET: Internet Protocol (IP)
AF_INET6: IP version 6 (IPv6) AF_INET6: IP version 6 (IPv6)
AF_UNIX: local channel, similar to pipes AF_UNIX: local channel, similar to pipes
AF_ISO: “In Search Of” (ISO) protocols AF_ISO: “In Search Of” (ISO) protocols
AF_NS: Xerox Network Systems protocols AF_NS: Xerox Network Systems protocols
@ -90,24 +90,24 @@ Field 3: Defines the length in bytes of the UDP header and data. Allows for data
perror("cannot create socket"); perror("cannot create socket");
return 0; return 0;
} }
printf("created socket: descriptor=%d\n", sockfd); printf("created socket: descriptor=%d\n", sockfd);
1.4. STEP 2: IDENTIFY/NAME THE SOCKET 1.4. STEP 2: IDENTIFY/NAME THE SOCKET
By naming the socket we are assigning a transport address to the socket (I.E. a port number in IP networking). This is more commonly referred to as “binding” an address. The bind system call is used to do this. In other words we are giving our server a unique address so that communication with our server can be established much like a person with a mailing address. They can receive communiques (letters) via their mailbox. Our server can do the same once it has a “bound” socket. By naming the socket we are assigning a transport address to the socket (I.E. a port number in IP networking). This is more commonly referred to as “binding” an address. The bind system call is used to do this. In other words we are giving our server a unique address so that communication with our server can be established much like a person with a mailing address. They can receive communiques (letters) via their mailbox. Our server can do the same once it has a “bound” socket.
The transport address is defined in the socket address structure. Since sockets can receive and send data using a myriad of communication interfaces, the interface is very general. Rather than accepting a port number as a parameter, it will look for a “sockaddr” (short for socket address)structure whose format is based off the address family we chose. The transport address is defined in the socket address structure. Since sockets can receive and send data using a myriad of communication interfaces, the interface is very general. Rather than accepting a port number as a parameter, it will look for a “sockaddr” (short for socket address)structure whose format is based off the address family we chose.
#include <sys/socket.h> contains the relevant “bind” call we will need. Since we already used it in STEP 1 we do not need to include it a second time. #include <sys/socket.h> contains the relevant “bind” call we will need. Since we already used it in STEP 1 we do not need to include it a second time.
Figure 1.4 Bind the Socket Figure 1.4 Bind the Socket
int int
bind(int socket, const struct sockaddr *address, socklen_t address_len); bind(int socket, const struct sockaddr *address, socklen_t address_len);
The first parameter “socket” is the socket we created in STEP 1 (sockfd) The first parameter “socket” is the socket we created in STEP 1 (sockfd)
The second parameter (sockaddr) will allow the operating system (OS) to read the first couple bytes that identify the address family. For UDP/IP networking we will use struct sockaddr_in, which is defined in the netinet/in.h system library. The second parameter (sockaddr) will allow the operating system (OS) to read the first couple bytes that identify the address family. For UDP/IP networking we will use struct sockaddr_in, which is defined in the netinet/in.h system library.
Defined: Defined:
@ -129,11 +129,11 @@ Figure 1.6
Before calling bind, we need to fill this struct. The three key parts we need to set are: Before calling bind, we need to fill this struct. The three key parts we need to set are:
1. sin_family 1. sin_family
The address family we used in STEP 1 (AF_INET). The address family we used in STEP 1 (AF_INET).
2. sin_port 2. sin_port
The port number (transport address). This can either be explicitly declared, or you can allow the OS to assign one. Since we are creating a server, ideally we would want to explicitly declare a well known port so that clients know where to address their messages. However for this particular tutorial we will use the generic 11111 (five ones). This will be defined directly beneath the include section of our code.(figure 1.1.7) The port number (transport address). This can either be explicitly declared, or you can allow the OS to assign one. Since we are creating a server, ideally we would want to explicitly declare a well known port so that clients know where to address their messages. However for this particular tutorial we will use the generic 11111 (five ones). This will be defined directly beneath the include section of our code.(figure 1.1.7)
Figure 1.7 Figure 1.7
#define SERV_PORT 11111 #define SERV_PORT 11111
@ -167,7 +167,7 @@ Before calling bind, we need to fill this struct. The three key parts we need to
Defined: Defined:
Figure 1.8 “recvfrom” Figure 1.8 “recvfrom”
int recvfrom(int socket, void* restrict buffer, size_t length, int recvfrom(int socket, void* restrict buffer, size_t length,
int socklen_t *restrict *src_len) int socklen_t *restrict *src_len)
5.1 PARAMETERS DEFINED 5.1 PARAMETERS DEFINED
@ -209,7 +209,7 @@ recvlen = recvfrom(sockfd, buf, MSGLEN, 0, (struct sockaddr *)&cliaddr, &addrlen
The server can use that address in sendto and send a message back to the recipients address. The server can use that address in sendto and send a message back to the recipients address.
Defined: Defined:
Figure 1.11 Figure 1.11
sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&cliaddr, addrlen) sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&cliaddr, addrlen)
With this our UDP/IP server is now up and running. We can listen for client connections on a specific port, and we can acknowledge to the client that we have received the communications. Click link for a sample of completed code. With this our UDP/IP server is now up and running. We can listen for client connections on a specific port, and we can acknowledge to the client that we have received the communications. Click link for a sample of completed code.
@ -274,7 +274,7 @@ Figure 1.14
int yourSocket = socket(domain, type, protocol); int yourSocket = socket(domain, type, protocol);
Example Code: Example Code:
Figure 1.15 Figure 1.15
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
err_sys("cannot create a socket."); err_sys("cannot create a socket.");
This method checks for a socket creation error, a good idea when setting up any socket implementation. Include the socket header: This method checks for a socket creation error, a good idea when setting up any socket implementation. Include the socket header:
@ -319,10 +319,10 @@ if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
We will begin by adding the following libraries to pull from. We will begin by adding the following libraries to pull from.
Figure 2.1 Figure 2.1
#include <cyassl/ssl.h> #include <cyassl/ssl.h>
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
1.2. Increase MSGLEN 1.2. Increase MSGLEN
Next change the size of our MSGLEN to 4096 to be more universal. This step is unnecessary if youre testing against the client.c located in cyassl/examples/client as it will only send a message of length 14 or so but why not be able to handle a little user input if we want to test against a friends client or something! Next change the size of our MSGLEN to 4096 to be more universal. This step is unnecessary if youre testing against the client.c located in cyassl/examples/client as it will only send a message of length 14 or so but why not be able to handle a little user input if we want to test against a friends client or something!
@ -337,7 +337,7 @@ if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1.3.3 Create ctx and sig_handler Method 1.3.3 Create ctx and sig_handler Method
Now we declare a CYASSL_CTX pointer and call it “ctx” for simplicity, and declare a void sig_handler method that takes a constant integer as an argument. Now we declare a CYASSL_CTX pointer and call it “ctx” for simplicity, and declare a void sig_handler method that takes a constant integer as an argument.
1.3.4 Declare AwaitDGram() 1.3.4 Declare AwaitDGram()
Finally we will declare a method AwaitDGram(). We will break our client handling out of main() and handle those connection in our new method. This is in preparation for Chapter 3 where we will be handling multiple client connections simultaneously.Your variable section should now look something like Figure 2.2: Finally we will declare a method AwaitDGram(). We will break our client handling out of main() and handle those connection in our new method. This is in preparation for Chapter 3 where we will be handling multiple client connections simultaneously.Your variable section should now look something like Figure 2.2:
@ -357,14 +357,14 @@ if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
Just below sig_handler insert the following lines: Just below sig_handler insert the following lines:
Figure 2.3 Figure 2.3
56 void AwaitDGram() 56 void AwaitDGram()
57 { 57 {
58 58
59 } 59 }
1.4.2 Move Variables from main() 1.4.2 Move Variables from main()
Literally cut and paste variable section from main() into our skeleton. Additionally add the variable “char ack”. This will be a reply message that we send to our clients. Ack is short for “Acknowledge”. So our clients have some sort of feedback letting them know that we received their communication successfully. See section 2.1.7.4 to see how ack is used in the code. Literally cut and paste variable section from main() into our skeleton. Additionally add the variable “char ack”. This will be a reply message that we send to our clients. Ack is short for “Acknowledge”. So our clients have some sort of feedback letting them know that we received their communication successfully. See section 2.1.7.4 to see how ack is used in the code.
1.4.3 Remove un-needed Variables and Move all Declarations Together 1.4.3 Remove un-needed Variables and Move all Declarations Together
@ -372,7 +372,7 @@ if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
With this change we will also rename “addrlen” to “clilen” to remind us that this socklen_t is the length of the clients address and not to be confused with our sockets address. We will no longer assign the length of “clilen” upon declaration either. That will be handled later in our program. Remove msgnum altogether. Take note: “recvlen” is being declared here however is not used until we have verified our client is encrypting with DTLS version 1.2. See sub-section 2.1.7.4 to see “recvlen” used in code. Our variable section should now look something like this: With this change we will also rename “addrlen” to “clilen” to remind us that this socklen_t is the length of the clients address and not to be confused with our sockets address. We will no longer assign the length of “clilen” upon declaration either. That will be handled later in our program. Remove msgnum altogether. Take note: “recvlen” is being declared here however is not used until we have verified our client is encrypting with DTLS version 1.2. See sub-section 2.1.7.4 to see “recvlen” used in code. Our variable section should now look something like this:
Figure 2.4 Figure 2.4
void AwaitDGram() void AwaitDGram()
{ {
int on = 1; int on = 1;
int res = 1; int res = 1;
@ -805,7 +805,7 @@ to:
1.2.3. 1.2.3.
A char* object to print a message that session resume is testing. A char* object to print a message that session resume is testing.
Figure 4.1 (1.2.1-1.2.3 Example code:) Figure 4.1 (1.2.1-1.2.3 Example code:)
CYASSL* sslResume = 0; CYASSL* sslResume = 0;
CYASSL_SESSION* session = 0; CYASSL_SESSION* session = 0;
char* srTest = "testing session resume"; char* srTest = "testing session resume";
@ -819,7 +819,7 @@ to:
2.3. 2.3.
Set up a new CyaSSL object for the resumption stage using sslResume. Set up a new CyaSSL object for the resumption stage using sslResume.
Figure 4.2 (2.1-2.3 Example code:) Figure 4.2 (2.1-2.3 Example code:)
CyaSSL_write(ssl, srTest, sizeof(srTest)); CyaSSL_write(ssl, srTest, sizeof(srTest));
session = CyaSSL_get_session(ssl); session = CyaSSL_get_session(ssl);
sslResume = CyaSSL_new(ctx); sslResume = CyaSSL_new(ctx);
@ -861,14 +861,14 @@ to:
Call CyaSSL_write with the same parameters as step A. only changing ssl to Call CyaSSL_write with the same parameters as step A. only changing ssl to
sslResume. sslResume.
Figure 4.5 (2.7 - 2.12 Example Code:) Figure 4.5 (2.7 - 2.12 Example Code:)
CyaSSL_set_fd(sslResume, sockfd); CyaSSL_set_fd(sslResume, sockfd);
CyaSSL_set_session(sslResume, session); CyaSSL_set_session(sslResume, session);
if (CyaSSL_connect(sslResume) != SSL_SUCCESS) if (CyaSSL_connect(sslResume) != SSL_SUCCESS)
err_sys("SSL_connect failed"); err_sys("SSL_connect failed");
if(CyaSSL_session_reused(sslResume)) if(CyaSSL_session_reused(sslResume))
printf("reused session id\n"); printf("reused session id\n");
else else
printf("didn't reuse session id!!!\n"); printf("didn't reuse session id!!!\n");
@ -909,7 +909,7 @@ fcntl(sockfd, F_SETFL, O_NONBLOCK);
NonBlockingDTLS_Connect(ssl); NonBlockingDTLS_Connect(ssl);
Replace: Replace:
Figure 4.9 Figure 4.9
if (CyaSSL_connect(sslResume) != SSL_SUCCESS) if (CyaSSL_connect(sslResume) != SSL_SUCCESS)
err_sys("SSL_connect failed"); err_sys("SSL_connect failed");
with: with:
@ -965,20 +965,20 @@ Figure 5.1.1 non blocking server model
2. Bind Socket 2. Bind Socket
3. Await DGram arrival 3. Await DGram arrival
4. Set socket to nonblocking <-------------- 4. Set socket to nonblocking <--------------
5. select | 5. select |
6. accept | 6. accept |
7. Read Message | 7. Read Message |
8. Reply to Message | 8. Reply to Message |
9. Loop to step 4----------------------------- 9. Loop to step 4-----------------------------
1.2 udp_read_connect (int) 1.2 udp_read_connect (int)
We previously had this code in the body of AwaitDGram() however we broke it out to reduce the size of AwaitDGram() as well as to improve readability of the code. This is just our method to “watch” for datagrams to arrive. We previously had this code in the body of AwaitDGram() however we broke it out to reduce the size of AwaitDGram() as well as to improve readability of the code. This is just our method to “watch” for datagrams to arrive.
Figure 5.2 watch for datagrams Figure 5.2 watch for datagrams
int udp_read_connect(int listenfd) int udp_read_connect(int listenfd)
{ {
int connfd; int connfd;
unsigned char b[1500]; unsigned char b[1500];
@ -1006,7 +1006,7 @@ Figure 5.1.1 non blocking server model
Here we will see the variable “select_ret” dress up in different costumes. In order to get a costume we reference method “dtls_select()” to see how different costumes are picked by “select_ret” (see figure 5.5) Based on the costume “select_ret” is wearing we will make some decisions. This method is pulled in directly from the library test.h in the cyassl libraries and can be found in the following location: Starting from the root directory of cyassl type “cd cyassl” this is where test.h is located. Search for NonBlockingSSL_Accept to see this code in its original format. Figure 5.3 has some very minor edits to make it work with our example server. Here we will see the variable “select_ret” dress up in different costumes. In order to get a costume we reference method “dtls_select()” to see how different costumes are picked by “select_ret” (see figure 5.5) Based on the costume “select_ret” is wearing we will make some decisions. This method is pulled in directly from the library test.h in the cyassl libraries and can be found in the following location: Starting from the root directory of cyassl type “cd cyassl” this is where test.h is located. Search for NonBlockingSSL_Accept to see this code in its original format. Figure 5.3 has some very minor edits to make it work with our example server.
Figure 5.3 NonBlockingSSL_Accept Figure 5.3 NonBlockingSSL_Accept
void NonBlockingSSL_Accept(CYASSL* ssl) void NonBlockingSSL_Accept(CYASSL* ssl)
{ {
int select_ret; int select_ret;
int currTimeout = 1; int currTimeout = 1;
@ -1056,7 +1056,7 @@ Figure 5.1.1 non blocking server model
Again this method is pulled in from test.h however modified slightly to work with our server. (removed un-necessary #ifdefs). Here is where we use fcntl to set our socket to a non-blocking state. Again this method is pulled in from test.h however modified slightly to work with our server. (removed un-necessary #ifdefs). Here is where we use fcntl to set our socket to a non-blocking state.
Figure 5.4 set nonblocking Figure 5.4 set nonblocking
235 static void dtls_set_nonblocking(int* listenfd) 235 static void dtls_set_nonblocking(int* listenfd)
236 { 236 {
237 int flags = fcntl(*listenfd, F_GETFL, 0); 237 int flags = fcntl(*listenfd, F_GETFL, 0);
238 if (flags < 0) { 238 if (flags < 0) {
@ -1070,11 +1070,11 @@ Figure 5.1.1 non blocking server model
246 } 246 }
247 } 247 }
1.5 Select() 1.5 Select()
Again this is pulled from test.h and modified to work with our server. Here you see how “select_ret” from section 5.1.3 picks a costume to wear as a result of given conditions. Again this is pulled from test.h and modified to work with our server. Here you see how “select_ret” from section 5.1.3 picks a costume to wear as a result of given conditions.
Figure 5.5 Picking a costume for select_ret Figure 5.5 Picking a costume for select_ret
249 static int dtls_select(int socketfd, int to_sec) 249 static int dtls_select(int socketfd, int to_sec)
250 { 250 {
251 fd_set recvfds, errfds; 251 fd_set recvfds, errfds;
252 int nfds = socketfd + 1; 252 int nfds = socketfd + 1;
@ -1138,22 +1138,22 @@ Figure 5.1.1 non blocking server model
buff[recvlen] = 0; buff[recvlen] = 0;
printf("I heard this:\"%s\"\n", buff); printf("I heard this:\"%s\"\n", buff);
} }
else { else {
printf("Connection Timed Out.\n"); printf("Connection Timed Out.\n");
} }
if (CyaSSL_write(ssl, ack, sizeof(ack)) < 0) { if (CyaSSL_write(ssl, ack, sizeof(ack)) < 0) {
printf("Write error.\n"); printf("Write error.\n");
cleanup = 1; cleanup = 1;
} }
printf("Reply sent:\"%s\"\n", ack); printf("Reply sent:\"%s\"\n", ack);
/* free allocated memory */ /* free allocated memory */
memset(buff, 0, sizeof(buff)); memset(buff, 0, sizeof(buff));
CyaSSL_free(ssl); CyaSSL_free(ssl);
/* End: Reply to the Client */ /* End: Reply to the Client */
} }
} }
This concludes the tutorial section on making a dtls wrapped This concludes the tutorial section on making a dtls wrapped
@ -1170,7 +1170,7 @@ enum {
TEST_TIMEOUT, TEST_TIMEOUT,
TEST_RECV_READY, TEST_RECV_READY,
TEST_ERROR_READY TEST_ERROR_READY
}; };
2.3. Add a DTLS selection function 2.3. Add a DTLS selection function
This is similar to the tcp_select() function in CyaSSL. This function will also call This is similar to the tcp_select() function in CyaSSL. This function will also call
@ -1207,7 +1207,7 @@ select():
2.4. NonBlocking DTLS connect function: 2.4. NonBlocking DTLS connect function:
This function calls the connect function and checks for various errors within the connection attempts. We placed it before the DatagramClient() function: This function calls the connect function and checks for various errors within the connection attempts. We placed it before the DatagramClient() function:
/*Connect using Nonblocking - DTLS version*/ /*Connect using Nonblocking - DTLS version*/
63 static void NonBlockingDTLS_Connect(CYASSL* ssl) 63 static void NonBlockingDTLS_Connect(CYASSL* ssl)
64 { 64 {
65 int ret = CyaSSL_connect(ssl); 65 int ret = CyaSSL_connect(ssl);
66 int error = CyaSSL_get_error(ssl, 0); 66 int error = CyaSSL_get_error(ssl, 0);