Documente Academic
Documente Profesional
Documente Cultură
Pthreads
Ing. Mauricio Mena Cortés
koitoer
28 de abril de 2009
1
Índice general
1. Prefacio 5
1.1. A quien lo lea: . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2. Instalación básica 7
2.1. Requerimientos del sistema . . . . . . . . . . . . . . . . . . . 7
2.2. Openssl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3. Creación de certificados 9
3.1. Explicaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.2. CA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.3. Certificado del servidor . . . . . . . . . . . . . . . . . . . . . 12
3.4. Certificado del cliente . . . . . . . . . . . . . . . . . . . . . . 17
4. Códigos Fuentes 23
4.1. SERVER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.2. CLIENTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.3. Compilación . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.4. MAKE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5. Servidor Multihilo 39
5.1. SERVER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
6. Conclusión 48
6.1. Problemas principales . . . . . . . . . . . . . . . . . . . . . . 48
6.1.1. Creación de certificados . . . . . . . . . . . . . . . . . 48
6.1.2. Firewall . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.2. Tutoriales futuros . . . . . . . . . . . . . . . . . . . . . . . . 51
6.3. Ideas Finales . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2
ÍNDICE GENERAL 3
6.4. Agradecimientos . . . . . . . . . . . . . . . . . . . . . . . . . 52
Índice de figuras
4
Parte 1
Prefacio
5
PARTE 1. PREFACIO 6
Instalación básica
1. GCC
2. GDB
3. OpenSSL
7
PARTE 2. INSTALACIÓN BÁSICA 8
2.2. Openssl
Con respecto al openssl su instalación solo consta de los siguientes pasos.
1. Crear el directorio
# mkdir /usr/src/
3. Descomprimir
# tar zxvf http://www.openssl.org/source/openssl-0.9.8k.tar.gz
4. Compilamos
# cd openssl-0.9.8k
# ./config
# make
# make test
# make install
Creación de certificados
3.1. Explicaciones
Ahora bien una vez instalado, OpenSSL nos servirá para crear los certifi-
cados que se necesitan, además de darnos la API, para trabajar con Sockets
de manera segura.
Para la creación de los certificados, en este caso necesitaremos tres, uno
que actúe como autoridad certificadora, uno que sea el del servidor y por
último el que se usará en el cliente.
client.pem Certificado del cliente. client.key Llave privada del cliente. cac-
ert.pem Certificado de Autoridad Certificadora. server.key Llave privada del
servidor. server.pem Certificado del servidor.
Para generarlos usaremos openssl, generando primero el de la autoridad
certificadora, para que firme digitalmente el del servidor y del cliente, estó de
la siguiente manera.
En este caso se crea primero la autoridad certificadora que seremos nos-
tros mismos, después de eso tendremos que hacer las peticiones para crear
dos nuevos certificados y por último firmarlos por medio de la autoridad
certificadora creada anteriormente.
3.2. CA
root@koitoersv:/home/koitoer# pwd
/home/koitoer
root@koitoersv:/home/koitoer# mkdir certs
9
PARTE 3. CREACIÓN DE CERTIFICADOS 10
root@koitoersv:/home/koitoer# cd certs/
root@koitoersv:/home/koitoer/certs# cp /usr/lib/ssl/misc/CA.sh
root@koitoersv:/home/koitoer/certs# cp /usr/lib/ssl/misc/CA.sh .
root@koitoersv:/home/koitoer/certs# ./CA.sh -newca
CA certificate filename (or enter to create)
root@koitoersv:/home/koitoer/certs# pwd
/home/koitoer/certs
root@koitoersv:/home/koitoer/certs# mkdir server_cert
root@koitoersv:/home/koitoer/certs# ls
CA.sh demoCA server_cert
root@koitoersv:/home/koitoer/certs# ./CA.sh -newreq
Generating a 1024 bit RSA private key
................++++++
...........................................................++++++
writing new private key to ’newkey.pem’
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that
will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished
Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter ’.’, the field will be left blank.
-----
Country Name (2 letter code) [MX]:
State or Province Name (full name) [Distrito Federal]:
Locality Name (eg, city) []:Koitoerserverland
Organization Name (eg, company) [Telecomunicaciones de Mexico]:koitoerserver
Organizational Unit Name (eg, section) []:koitoerservers
Common Name (eg, YOUR name) []:koitoer.server
Email Address []:koitoer.server@gmail.com
PARTE 3. CREACIÓN DE CERTIFICADOS 13
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
61:4A:1E:46:8A:EA:19:39:AE:C2:5D:05:3F:2A:68:
E6:69:AD:80
X509v3 Authority Key Identifier:
keyid:EC:2A:55:C2:8C:1E:A9:CD:0E:DA:AA:8F:84:
34:74:54:54:A6:46:2A
También lı́nea 62
62 REQ − new − keyoutnewkey.pem − outnewreq.pemDAYS
Cambiamos por :
62 REQ − new − nodes − keyoutnewkey.pem − outnewreq.pemDAYS
74:54:54:A6:46:2A
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
89:4C:83:EA:4B:54:C2:BB:16:80:A7:96:15:D7:42
:11:82:2E:1C:D6
X509v3 Authority Key Identifier:
keyid:EC:2A:55:C2:8C:1E:A9:CD:0E:DA:AA:8F:84
:34:74:54:54:A6:46:2A
-----END CERTIFICATE-----
Signed certificate is in newcert.pem
root@koitoersv:/home/koitoer/certs# mkdir
CA.sh demoCA/ newcert.pem newkey.pem newreq.pem server_cert/
root@koitoersv:/home/koitoer/certs# mkdir cliente_cert
root@koitoersv:/home/koitoer/certs# cp newkey.pem cliente.key
root@koitoersv:/home/koitoer/certs# cp newcert.pem cliente.pem
root@koitoersv:/home/koitoer/certs# cp new* cliente
cliente_cert/ cliente.key cliente.pem
root@koitoersv:/home/koitoer/certs# cp new* cliente_cert/
root@koitoersv:/home/koitoer/certs# ls
CA.sh cliente.key demoCA newkey.pem server_cert
cliente_cert cliente.pem newcert.pem newreq.pem
root@koitoersv:/home/koitoer/certs# cp cliente.* cliente
cliente_cert/ cliente.key cliente.pem
root@koitoersv:/home/koitoer/certs# cp cliente.* cliente_cert/
root@koitoersv:/home/koitoer/certs# ls
CA.sh cliente.key demoCA newkey.pem server_cert
cliente_cert cliente.pem newcert.pem newreq.pem
root@koitoersv:/home/koitoer/certs# rm cliente.*
root@koitoersv:/home/koitoer/certs# ls
CA.sh cliente_cert demoCA newcert.pem newkey.pem newreq.pem server_cert
root@koitoersv:/home/koitoer/certs# rm new*
root@koitoersv:/home/koitoer/certs# ls
CA.sh cliente_cert demoCA server_cert
root@koitoersv:/home/koitoer/certs# cd cliente_cert/
root@koitoersv:/home/koitoer/certs/cliente_cert# ls
cliente.key cliente.pem newcert.pem newkey.pem newreq.pem
root@koitoersv:/home/koitoer/certs/cliente_cert#
4.1. SERVER
#include <s t d i o . h>
#include <e r r n o . h>
#include <u n i s t d . h>
#include <m a l l o c . h>
#include <s t r i n g . h>
#include <s y s / s o c k e t . h>
/∗ Lı́ b r e r i a para l o s s o c k e t ∗/
#include <r e s o l v . h>
#include <netdb . h>
#include <o p e n s s l / s s l . h>
/∗ Lı́ b r e r i a de o p e n s s l para l a f u n c i o n a l i d a d y c o n t e x t o s ∗/
#include <o p e n s s l / e r r . h>
/∗ Lı́ b r e r i a de o p e n s s l para e r r o r e s ∗/
#define FAIL −1
23
PARTE 4. CÓDIGOS FUENTES 24
/∗−−− C r e a r S o c k e t −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗ Crea un s o c k e t normal para i m p l e m e n t a r l e SSL −−−−−∗/
int C r e a r S o c k e t ( int p o r t ) {
int sd ;
struct s o c k a d d r i n addr ;
sd = s o c k e t ( PF INET , SOCK STREAM, 0 ) ;
b z e r o (&addr , s i z e o f ( addr ) ) ;
addr . s i n f a m i l y = AF INET ;
addr . s i n p o r t = h t o n s ( p o r t ) ;
addr . s i n a d d r . s a d d r = INADDR ANY;
i f ( bind ( sd , ( struct s o c k a d d r ∗ )&addr , s i z e o f ( addr ) ) != 0 )
{
perror ( ” Error a l l i g a r e l socket ” ) ;
abort () ;
}
i f ( l i s t e n ( sd , 1 0 ) != 0 ) {
p e r r o r ( ” E r r o r en e l l i s t e n ” ) ;
abort () ;
}
return sd ;
}
/∗−−− I n i c i a r C T X S e r v i d o r −−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗ I n i c i a l i z a e l s e r v i d o r y c r e a e l c o n t e x t o s e r v e r −∗/
} else {
p r i n t f ( ”No s e pudo e s t a b l e c e r \n” ) ;
}
return c t x ;
}
/∗−−− C a r g a r C e r t i f i c a d o s −−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗ Carga l o s c e r t i f i c a d o s d e l s e r v i d o r y CA −−−−−−−∗/
/∗−−− M o s t r a r C e r t i f i c a d o s −−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗ Imprime l o s c e r t i f i c a d o s −−−−−−−−−−−−−−−−−−−−−−−−−∗/
void M o s t r a r C e r t i f i c a d o s ( SSL∗ s s l )
{ X509 ∗ c e r t ;
char ∗ l i n e ;
PARTE 4. CÓDIGOS FUENTES 26
void S e r v i d o r ( SSL∗ s s l ) {
/∗ P rop o rci on a l a f u n c i o n a l i d a d d e l s e r v i d o r ∗/
char buf [ 1 0 2 4 ] ;
char r e p l y [ 1 0 2 4 ] ;
int sd , b y t e s ;
const char∗ HTMLecho=” Esto s o l o e s un mensaje ISO01 |EOF” ;
p r i n t f ( ” I n i c i a S e r v i d o r \n” ) ;
i f ( S S L a c c e p t ( s s l ) == FAIL ) {
/∗ Se hace e l a c c e p t − SSL ∗/
p r i n t f ( ”Hubo un e r r o r en e l S S L a c c e p t \n” ) ;
ERR print errors fp ( stderr ) ;
} else {
p r i n t f ( ” S S L a c c e p t f u e e x i t o s o \n” ) ;
MostrarCertificados ( s s l ) ;
/∗ O b t i e n e e imprime l o s c e r t i f i c a d o s ∗/
b y t e s = SSL read ( s s l , buf , s i z e o f ( buf ) ) ;
/∗ Espera una p e t i c i o n d e l c l i e n t e ∗/
i f ( bytes > 0 ) {
buf [ b y t e s ] = 0 ;
PARTE 4. CÓDIGOS FUENTES 27
i f ( count != 2 ) {
p r i n t f ( ”Uso : %s <portnum>\n” , s t r i n g s [ 0 ] ) ;
exit (0) ;
}
portnum = s t r i n g s [ 1 ] ;
ctx = IniciarCTXServidor () ;
/∗ Se i n i c i a l i z a e l SSL para e l c o n t e x t o S e r v e r ∗/
C a r g a r C e r t i f i c a d o s ( ctx , ” s e r v . pem” , ” s e r v . key ” ) ;
/∗ Carga l o s c e r t i f i c a d o s d e l s e r v i d o r ∗/
s e r v e r = C r e a r S o c k e t ( a t o i ( portnum ) ) ;
/∗ Crea e l s o c k e t normal para e l s e r v i d o r ∗/
p r i n t f ( ” Esperando por c o n e x i o n e s [ %d ] \n” , s e r v e r ) ;
PARTE 4. CÓDIGOS FUENTES 28
p r i n t f ( ” I n i c i a a a c e p t a r c o n e x i o n e s \n” ) ;
while ( 1 ) {
struct s o c k a d d r i n addr ;
int l e n = s i z e o f ( addr ) ;
SSL ∗ s s l ;
int c l i e n t = a c c e p t ( s e r v e r , ( struct s o c k a d d r ∗ )&addr , &
len ) ;
/∗ Está en e s t a d o de a c e p t a r c o n e x i o n e s ∗/
p r i n t f ( ” Connection : %d: %d\n” ,
i n e t n t o a ( addr . s i n a d d r ) , n t o h s ( addr . s i n p o r t ) ) ;
/∗ Muestra l o s d a t o s d e l u s u a r i o que s e c o n e c t a ∗/
s s l = SSL new ( c t x ) ;
/∗ Se o b t i e n e e l nuevo e s t a d o SSL con su c o n t e x t o ∗/
SSL set fd ( ssl , c l i e n t ) ;
/∗ Se a s i g n a e l s o c k e t a l e s t a d o SSL para c l i e n t e ∗/
Servidor ( s s l ) ;
/∗ P ro po rci on a l a f u n c i o n a l i d a d d e l s e r v i d o r ( s e r v i c i o ) ∗/
}
close ( server ) ;
/∗ C i e r r a e l s o c k e t d e l s e r v i d o r ∗/
SSL CTX free ( c t x ) ;
/∗ L i b e r a l a c o n e x i ó n ∗/
}
/∗−−− C r e a r S o c k e t −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗ Crea un s o c k e t normal para i m p l e m e n t a r l e SSL −−−−−∗/
int C r e a r S o c k e t ( int p o r t ) {
int sd ;
struct s o c k a d d r i n addr ;
sd = s o c k e t ( PF INET , SOCK STREAM, 0 ) ;
b z e r o (&addr , s i z e o f ( addr ) ) ;
addr . s i n f a m i l y = AF INET ;
addr . s i n p o r t = h t o n s ( p o r t ) ;
addr . s i n a d d r . s a d d r = INADDR ANY;
i f ( bind ( sd , ( struct s o c k a d d r ∗ )&addr , s i z e o f ( addr ) ) != 0 )
{
perror ( ” Error a l l i g a r e l socket ” ) ;
abort () ;
}
i f ( l i s t e n ( sd , 1 0 ) != 0 ) {
p e r r o r ( ” E r r o r en e l l i s t e n ” ) ;
abort () ;
}
return sd ;
}
/∗−−− I n i c i a r C T X S e r v i d o r −−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗ I n i c i a l i z a e l s e r v i d o r y c r e a e l c o n t e x t o s e r v e r −∗/
PARTE 4. CÓDIGOS FUENTES 30
/∗−−− C a r g a r C e r t i f i c a d o s −−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗ Carga l o s c e r t i f i c a d o s d e l s e r v i d o r y CA −−−−−−−∗/
abort () ;
} else {
p r i n t f ( ” L l a v e c a r g a d a . \n” ) ;
}
/∗ Se hace una v e r i f i c a c i ó n de l a l l a v e ∗/
i f ( ! SSL CTX check private key ( ctx ) ) {
p r i n t f ( ”No s e pudo u s a r e l a r c h i v o de c e r t i f i c a d o \n” ) ;
f p r i n t f ( s t d e r r , ”La l l a v e p r i m a r i a no c o r r e s p o n d e \n” ) ;
abort () ;
} else {
p r i n t f ( ” C e r t i f i c a d o y L l a v e v a l i d o s . \n” ) ;
}
}
/∗−−− M o s t r a r C e r t i f i c a d o s −−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗ Imprime l o s c e r t i f i c a d o s −−−−−−−−−−−−−−−−−−−−−−−−−∗/
void M o s t r a r C e r t i f i c a d o s ( SSL∗ s s l )
{ X509 ∗ c e r t ;
char ∗ l i n e ;
void S e r v i d o r ( SSL∗ s s l ) {
/∗ P rop o rci on a l a f u n c i o n a l i d a d d e l s e r v i d o r ∗/
char buf [ 1 0 2 4 ] ;
char r e p l y [ 1 0 2 4 ] ;
int sd , b y t e s ;
const char∗ HTMLecho=” Esto s o l o e s un mensaje ISO01 |EOF” ;
p r i n t f ( ” I n i c i a S e r v i d o r \n” ) ;
i f ( S S L a c c e p t ( s s l ) == FAIL ) {
/∗ Se hace e l a c c e p t − SSL ∗/
p r i n t f ( ”Hubo un e r r o r en e l S S L a c c e p t \n” ) ;
ERR print errors fp ( stderr ) ;
} else {
p r i n t f ( ” S S L a c c e p t f u e e x i t o s o \n” ) ;
MostrarCertificados ( s s l ) ;
/∗ O b t i e n e e imprime l o s c e r t i f i c a d o s ∗/
b y t e s = SSL read ( s s l , buf , s i z e o f ( buf ) ) ;
/∗ Espera una p e t i c i ó n d e l c l i e n t e ∗/
i f ( bytes > 0 ) {
buf [ b y t e s ] = 0 ;
p r i n t f ( ” Mensaje c l i e n t e : \” %s \”\n” , buf ) ;
s p r i n t f ( r e p l y , HTMLecho , buf ) ;
/∗ Imprime p e t i c i ó n d e l c l i e n t e ∗/
sleep (15) ;
SSL write ( s s l , reply , s t r l e n ( reply ) ) ;
/∗ Envı́a una r e s p u e s t a a l c l i e n t e ∗/
}
else
ERR print errors fp ( stderr ) ;
}
sd = S S L g e t f d ( s s l ) ;
/∗ O b t i e n e l a c o n e x i ó n d e l s o c k e t ∗/
SSL free ( s s l ) ;
/∗ L i b e r a e l e s t a d o SSL d e l c l i e n t e ∗/
c l o s e ( sd ) ;
/∗ C i e r r a l a c o n e x i ó n a l c l i e n t e ∗/
}
/∗ Se va a u s a r para e l s o c k e t d e l s e r v i d o r ∗/
char ∗ portnum ;
/∗ Se usa como e l número de p u e r t o ∗/
SSL library init () ;
/∗ I n i c i a l i z a c i ó n de l a s l i b r e r i a s SSL !IMPORTANTE” ∗/
i f ( count != 2 ) {
p r i n t f ( ”Uso : %s <portnum>\n” , s t r i n g s [ 0 ] ) ;
exit (0) ;
}
portnum = s t r i n g s [ 1 ] ;
ctx = IniciarCTXServidor () ;
/∗ Se i n i c i a l i z a e l SSL para e l c o n t e x t o S e r v e r ∗/
C a r g a r C e r t i f i c a d o s ( ctx , ” s e r v . pem” , ” s e r v . key ” ) ;
/∗ Carga l o s c e r t i f i c a d o s d e l s e r v i d o r ∗/
s e r v e r = C r e a r S o c k e t ( a t o i ( portnum ) ) ;
/∗ Crea e l s o c k e t normal para e l s e r v i d o r ∗/
p r i n t f ( ” Esperando por c o n e x i o n e s [ %d ] \n” , s e r v e r ) ;
p r i n t f ( ” I n i c i a a a c e p t a r c o n e x i o n e s \n” ) ;
while ( 1 ) {
struct s o c k a d d r i n addr ;
int l e n = s i z e o f ( addr ) ;
SSL ∗ s s l ;
int c l i e n t = a c c e p t ( s e r v e r , ( struct s o c k a d d r ∗ )&addr , &
len ) ;
/∗ Esta en e s t a d o de a c e p t a r c o n e x i o n e s ∗/
p r i n t f ( ” Connection : %d: %d\n” ,
i n e t n t o a ( addr . s i n a d d r ) , n t o h s ( addr . s i n p o r t ) ) ;
/∗ Muestra l o s d a t o s d e l u s u a r i o que s e c o n e c t a ∗/
s s l = SSL new ( c t x ) ;
/∗ Se o b t i e n e e l nuevo e s t a d o SSL con su c o n t e x t o ∗/
SSL set fd ( ssl , c l i e n t ) ;
/∗ Se a s i g n a e l s o c k e t a l e s t a d o SSL para c l i e n t e ∗/
Servidor ( s s l ) ;
PARTE 4. CÓDIGOS FUENTES 34
/∗ P ro po rci on a l a f u n c i o n a l i d a d d e l s e r v i d o r ( s e r v i c i o ) ∗/
}
close ( server ) ;
/∗ C i e r r a e l s o c k e t d e l s e r v i d o r ∗/
SSL CTX free ( c t x ) ;
/∗ L i b e r a l a c o n e x i ó n ∗/
}
Como veran el código es bastante similar, solo que en esta ocasión usamos
el contexto de cliente.
4.3. Compilación
Ahora vamos a correr el servidor y el cliente, obviamente el servidor va
primero ya que si no se hace en ese orden, no tendrı́amos hacia donde conec-
tarnos para recibir el servicio, pero antes de ejecutarlos, compilemos:
root@koitoersv:/media/KINGSTON/Tutorial/Final/ServidorSSL#
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/ssl/lib
root@koitoersv:/media/KINGSTON/Tutorial/Final/ServidorSSL# pwd
/media/KINGSTON/Tutorial/Final/ServidorSSL
root@koitoersv:/media/KINGSTON/Tutorial/Final/ServidorSSL# make server
gcc -g -c server.c
gcc -o server server.o -L/usr/local/ssl/include/
-L/usr/local/ssl/lib -lssl -lcrypto -lnsl -ldl
root@koitoersv:/media/KINGSTON/Tutorial/Final/ServidorSSL# ls
cacert.pem Makefile server server.c server.key server.o server.pem
root@koitoersv:/media/KINGSTON/Tutorial/Final/ServidorSSL#
root@koitoersv:/media/KINGSTON/Tutorial/Final/ServidorSSL#
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/ssl/lib
koitoer@koitoersv:/media/KINGSTON/Tutorial/Final/ClienteSSL$ pwd
/media/KINGSTON/Tutorial/Final/ClienteSSL
koitoer@koitoersv:/media/KINGSTON/Tutorial/Final/ClienteSSL$ make cliente
gcc -g -c cliente.c
gcc -o cliente cliente.o -L/usr/local/ssl/include/
PARTE 4. CÓDIGOS FUENTES 35
4.4. MAKE
Para compilar más fácilmente podemos hacer uso de un Makefile, recor-
dando su sintaxis.
CC = gcc
PARTE 4. CÓDIGOS FUENTES 37
server: server.o
$(CC) -o server server.o -L/usr/local/ssl/include/
-L/usr/local/ssl/lib -lssl -lcrypto -lnsl -ldl
server.o: server.c
$(CC) -g -c server.c
cliente: cliente.o
$(CC) -o cliente cliente.o -L/usr/local/ssl/include/
-L/usr/local/ssl/lib -lssl -lcrypto -lnsl -ldl
cliente.o: cliente.c
$(CC) -g -c cliente.c
cipher:
/usr/local/ssl/bin/openssl ciphers -v ’ALL:!ADH:@STRENGTH’
clean:
rm *.o
Bien con esto tenemos un cliente SSL y un servidor SSL, que sólo se
mandan mensaje entre sı́. Si ejecutamos varios clientes a la vez, veremos que
el servidor sólo podrá responder a uno por uno, aunque los otros los tenga
en una cola tipo FIFO. Por lo que ahora programaremos un servidor que
acepte varios clientes a la vez, esto lo haremos usando el mismo certificado
del servidor, ya previamente hecho.
PARTE 4. CÓDIGOS FUENTES 38
Servidor Multihilo
5.1. SERVER
Hasta este punto hemos logrado un server que acepta conexiones pero solo
una a la vez, es cierto que tiene una cola de espera, pero no les puede dar
servicio a más de un cliente a la vez, como lo pueden corroborar si ejecutan
en dos consolas a dos clientes, ya que en el código del servidor puse un sleep
5 que ponen en espera al cliente 5 segundos, entonces en este caso nuestro
servidor sólo atiende a uno a la vez, pero vamos que es un servidor si no puede
dar servicio a más de un cliente a la vez. Para lograr lo antes mencionado
haremos uso de la implementación de pthread, que es conocido como POSIX
Thread.
Para esto no deseo modificar los codigos anteriores, ni decirles que parte se
modifica, ni que lı́neas, ya que puede resultar confuso y tal vez no funcione al
final, por lo que hacer un nuevo servidor en otro fichero, en el caso del cliente
no tendremos que hacerle ninguna modificación debido a que la funcionalidad
de multihilos la da el servidor no el cliente. Otra cosa que se tendrá que
modificar es el makefile, ya que al usar pthread deberemos de usar -lpthread
al compilar nuestros programas, ademas de incluir lı́brerias extras.
En el código del serverthread.c he quitado todos los comentarios anteriores
del SSL, y sólo deje los que explican la parte de los hilos y concurrencia.
39
PARTE 5. SERVIDOR MULTIHILO 40
/∗−−− C r e a r S o c k e t −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗ Crea un s o c k e t normal para i m p l e m e n t a r l e SSL −−−−−∗/
int C r e a r S o c k e t ( int p o r t ) {
int sd ;
struct s o c k a d d r i n addr ;
/∗−−− I n i c i a r C T X S e r v i d o r −−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗ I n i c i a l i z a e l s e r v i d o r y c r e a e l c o n t e x t o s e r v e r −∗/
i f ( S S L C T X s e t c i p h e r l i s t ( ctx , ”DES−CBC3−MD5” ) == 1 ) {
p r i n t f ( ” S i s e pudo e s t a b l e c e r \n” ) ;
} else {
p r i n t f ( ”No s e pudo e s t a b l e c e r \n” ) ;
}
return c t x ;
}
/∗−−− C a r g a r C e r t i f i c a d o s −−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗ Carga l o s c e r t i f i c a d o s d e l s e r v i d o r y CA −−−−−−−∗/
i f ( S S L C T X u s e c e r t i f i c a t e f i l e ( ctx , C e r t F i l e ,
SSL FILETYPE PEM) <= 0 ) {
p r i n t f ( ”No s e pudo u s a r e l a r c h i v o de c e r t i f i c a d o \n” ) ;
ERR print errors fp ( stderr ) ;
abort () ;
} else {
p r i n t f ( ” C e r t i f i c a d o c a r g a d o \n” ) ;
}
i f ( S S L C T X u s e P r i v a t e K e y f i l e ( ctx , KeyFile ,
SSL FILETYPE PEM) <= 0 ) {
p r i n t f ( ”No s e pudo u s a r e l a r c h i v o de l l a v e \n” ) ;
ERR print errors fp ( stderr ) ;
abort () ;
PARTE 5. SERVIDOR MULTIHILO 42
} else {
p r i n t f ( ” L l a v e c a r g a d a . \n” ) ;
}
p r i n t f ( ” C e r t i f i c a d o y L l a v e v a l i d o s . \n” ) ;
}
}
/∗−−− M o s t r a r C e r t i f i c a d o s −−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗ Imprime l o s c e r t i f i c a d o s −−−−−−−−−−−−−−−−−−−−−−−−−∗/
void M o s t r a r C e r t i f i c a d o s ( SSL∗ s s l )
{ X509 ∗ c e r t ;
char ∗ l i n e ;
void ∗ S e r v i d o r ( void ∗ t h r e a d a r g ) {
char buf [ 1 0 2 4 ] ;
char r e p l y [ 1 0 2 4 ] ;
int sd , b y t e s ;
const char∗ HTMLecho=” Esto s o l o e s e l mensaje de mi s e r v i d o r
SSL m u l t i h i l o ” ;
/∗ P a rs e r de l o s d a t o s de l a e s t r u c t u r a a v a r i a b l e s ∗/
my data = ( struct t h r e a d d a t a ∗ ) t h r e a d a r g ;
t a s k i d = my data−>t h r e a d i d ;
SSL ∗ s s l = my data−>s s l s o c k e t ;
p r i n t f ( ” I n i c i a S e r v i d o r \n” ) ;
i f ( S S L a c c e p t ( s s l ) == FAIL ) {
p r i n t f ( ”Hubo un e r r o r en e l S S L a c c e p t \n” ) ;
ERR print errors fp ( stderr ) ;
} else {
p r i n t f ( ” S S L a c c e p t f u e e x i t o s o \n” ) ;
MostrarCertificados ( s s l ) ;
b y t e s = SSL read ( s s l , buf , s i z e o f ( buf ) ) ;
i f ( bytes > 0 ) {
buf [ b y t e s ] = 0 ;
p r i n t f ( ” Mensaje c l i e n t e : \” %s \”\n” , buf ) ;
s p r i n t f ( r e p l y , HTMLecho , buf ) ;
sleep (5) ;
SSL write ( s s l , reply , s t r l e n ( reply ) ) ;
}
else
ERR print errors fp ( stderr ) ;
}
sd = S S L g e t f d ( s s l ) ;
SSL free ( s s l ) ;
c l o s e ( sd ) ;
}
PARTE 5. SERVIDOR MULTIHILO 44
i f ( count != 2 ) {
p r i n t f ( ”Uso : %s <portnum>\n” , s t r i n g s [ 0 ] ) ;
exit (0) ;
}
portnum = s t r i n g s [ 1 ] ;
ctx = IniciarCTXServidor () ;
C a r g a r C e r t i f i c a d o s ( ctx , ” s e r v . pem” , ” s e r v . key ” ) ;
s e r v e r = C r e a r S o c k e t ( a t o i ( portnum ) ) ;
p r i n t f ( ” Esperando por c o n e x i o n e s [ %d ] \n” , s e r v e r ) ;
p r i n t f ( ” I n i c i a a a c e p t a r c o n e x i o n e s \n” ) ;
while ( 1 ) {
struct s o c k a d d r i n addr ;
SSL ∗ s s l ;
int l e n = s i z e o f ( addr ) ;
int c l i e n t = a c c e p t ( s e r v e r , ( struct s o c k a d d r ∗ )&addr , &
len ) ;
p r i n t f ( ” Connection : %d: %d\n” ,
i n e t n t o a ( addr . s i n a d d r ) , n t o h s ( addr . s i n p o r t ) ) ;
s s l = SSL new ( c t x ) ;
PARTE 5. SERVIDOR MULTIHILO 45
/∗ Se c r e a c o n t e x t o ∗/
SSL set fd ( ssl , c l i e n t ) ;
t++;
/∗ Se da número de p t h r e a d ∗/
thread data array [ t ] . thread id = t ;
/∗ Se l e da e l i d d e l t h r e a d a l t h r e a d ∗/
t h r e a d d a t a a r r a y [ t ] . message = s s l ;
/∗ Se l e da e l a s i g n a e l c o n t e x t o de l a c o n e x i ó n a l t h r e a d ∗/
r c = p t h r e a d c r e a t e (& t h r e a d s [ t ] , NULL, S e r v l e t , ( void ∗ )
&t h r e a d d a t a a r r a y [ t ] ) ;
/∗ Se c r e a e l h i l o y s e l e manda l a e s t r u c t u r a l l e n a d a
p r e v i a m e n t e ∗/
}
close ( server ) ;
SSL CTX free ( c t x ) ;
}
root@koitoersv:/media/KINGSTON/Tutorial/Final/ServidorSSLMultihilo#
make serverthread
gcc -c -o serverthread.o serverthread.c
gcc -o serverthread serverthread.o -L/usr/local/ssl/include/
-L/usr/local/ssl/lib -lssl -lcrypto -lnsl -ldl -lpthread
root@koitoersv:/media/KINGSTON/Tutorial/Final/ServidorSSLMultihilo#
48
PARTE 6. CONCLUSIÓN 49
Lo que se tiene que revisar es el openssl.cnf para saber a dónde está apuntando
la creación de los certificados.
6.1.2. Firewall
Otro punto importante es que al usar sockets, ocupamos una o varias
direcciones IP’s y puertos, por lo que si elegimos un puerto por debajo del
1024 tendremos que usar permisos de root, además de que dependiendo de
la configuración los puertos pueden estar bloqueados por un firewall, por lo
que tendremos que configurarlo para permitir el acceso a éstos. En este caso
haremos uso de iptables.
#netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 *:1025 *:* LISTEN
tcp 0 0 localhost:50246 localhost:1025 ESTABLISHED
tcp 0 0 localhost:1025 localhost:50246 ESTABLISHED
tcp 0 0 localhost:50245 localhost:1025 TIME_WAIT
6.4. Agradecimientos
Un agradecimiento muy especial Martha Velasco Jiménez, por la valiosa
corrección que hizo a este documento, GRACIAS.