I am not able toload client certificate on ssl connection, so that server can authenticate it. What may be the issue ? LoadCertificates() function is working fine for loading server certificate. I am able to get server certificate on client end. But not able to get client certificate on server end.
Also I want to vertify that the certificates are signed by correct CA. I have CA certificate on both ends. Can I do that ?
//SSL-Client.c
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define FAIL -1
int OpenConnection(const char *hostname, int port)
{ int sd;
struct hostent *host;
struct sockaddr_in addr;
if ( (host = gethostbyname(hostname)) == NULL )
{
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
close(sd);
perror(hostname);
abort();
}
return sd;
}
SSL_CTX* InitCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
method = TLSv1_2_client_method(); /* Create new client-method instance */
ctx = SSL_CTX_new(method); /* Create new context */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if ( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line); /* free the malloc'ed string */
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line); /* free the malloc'ed string */
X509_free(cert); /* free the malloc'ed certificate copy */
}
else
printf("Info: No client certificates configured.\n");
}
int main(int count, char *strings[])
{ SSL_CTX *ctx;
int server;
SSL *ssl;
char buf[1024];
int bytes;
char *hostname, *portnum;
if ( count != 3 )
{
printf("usage: %s <hostname> <portnum>\n", strings[0]);
exit(0);
}
SSL_library_init();
hostname=strings[1];
portnum=strings[2];
ctx = InitCTX();
LoadCertificates(ctx, "cert.pem", "key.pem");
server = OpenConnection(hostname, atoi(portnum));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
if ( SSL_connect(ssl) == FAIL ) /* perform the connection */
ERR_print_errors_fp(stderr);
else
{ char *msg = "Hello???";
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl); /* get any certs */
SSL_write(ssl, msg, strlen(msg)); /* encrypt & send message */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
buf[bytes] = 0;
printf("Received: \"%s\"\n", buf);
SSL_free(ssl); /* release connection state */
}
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
Server.c
//SSL-Server.c
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#define FAIL -1
int OpenListener(int port)
{ int sd;
struct sockaddr_in addr;
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("can't bind port");
abort();
}
if ( listen(sd, 10) != 0 )
{
perror("Can't configure listening port");
abort();
}
return sd;
}
int isRoot()
{
if (getuid() != 0)
{
return 0;
}
else
{
return 1;
}
}
SSL_CTX* InitServerCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
method = TLSv1_2_server_method(); /* create new server-method instance */
ctx = SSL_CTX_new(method); /* create new context from method */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
if ( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates.\n");
}
void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{ char buf[1024];
char reply[1024];
int sd, bytes;
const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
ShowCerts(ssl); /* get any certificates */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( bytes > 0 )
{
buf[bytes] = 0;
printf("Client msg: \"%s\"\n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
SSL_write(ssl, reply, strlen(reply)); /* send reply */
}
else
ERR_print_errors_fp(stderr);
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
}
int main(int count, char *strings[])
{ SSL_CTX *ctx;
int server;
char *portnum;
if(!isRoot())
{
printf("This program must be run as root/sudo user!!");
exit(0);
}
if ( count != 2 )
{
printf("Usage: %s <portnum>\n", strings[0]);
exit(0);
}
SSL_library_init();
portnum = strings[1];
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, "mycert.pem", "mycert.pem"); /* load certs */
server = OpenListener(atoi(portnum)); /* create server socket */
while (1)
{ struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
}
close(server); /* close server socket */
SSL_CTX_free(ctx); /* release context */
}
You should be calling the API SSL_CTX_set_verify and passing SSL_VERIFY_PEER as input to the second parameter mode.
In TLS, client requests a certificate from server depending on the cipher suites exchanged, whereas the server requests the certificate from client only when you explicitly tell it do so as client authentication is optional and not cipher suite driven. When you set the SSL_VERIFY_PEER mode, server will explicitly send a Certificate Request message to Client and request for a certificate and verify it.
You can also verify if a Certificate Request message is going from Server to Client using a Packet Capture.
Related
I am using Microsoft Visual Studio 2010 and wolfSSL 3.7.0.
I create server context with these functions:
WOLFSSL_CTX *sslContext = wolfSSL_CTX_new(wolfTLSv1_2_server_method());
if(!sslContext)
{
closesocket(socketListen);
return FALSE;
}
wolfSSL_CTX_use_certificate_buffer(sslContext, (unsigned char*)szServerCert, strlen(szServerCert), SSL_FILETYPE_PEM);
wolfSSL_CTX_use_PrivateKey_buffer(sslContext, (unsigned char*)szServerKey, strlen(szServerKey), SSL_FILETYPE_PEM);
It is OK. Then, I accept the connection, create WOLFSSL* context and associate it with my socket descriptor:
WOLFSSL *ssl = wolfSSL_new(sslContext);
wolfSSL_set_fd(ssl, Socket);
CHAR Buffer[1024];
int retVal = wolfSSL_read(ssl, Buffer, 1024);
But when I try to connect to 127.0.0.1:443 via browser, wolfSSL_read() returns 0. wolfSSL_get_error() returns -397 (SOCKET_PEER_CLOSED_E). Browser shows me that page is still loading. What is the reason?
wolfSSL provides a good reference example here: https://github.com/wolfSSL/wolfssl-examples/blob/master/tls/server-tls.c
Please find referenced code below:
/* server-tls.c
*
* Copyright (C) 2006-2015 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*=============================================================================
*
* This is a super basic example of what a TCP Server secured with TLS 1.2
* might look like. This server can also resume the session if a client
* inadvertantly disconnects.
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
/* include the wolfSSL library for our TLS 1.2 security */
#include <wolfssl/ssl.h>
#define DEFAULT_PORT 11111
int AcceptAndRead(WOLFSSL_CTX* ctx, socklen_t sockfd, struct sockaddr_in
clientAddr);
int AcceptAndRead(WOLFSSL_CTX* ctx, socklen_t sockfd, struct sockaddr_in
clientAddr)
{
/* Create our reply message */
const char reply[] = "I hear ya fa shizzle!\n";
socklen_t size = sizeof(clientAddr);
/* Wait until a client connects */
socklen_t connd = accept(sockfd, (struct sockaddr *)&clientAddr, &size);
/* If fails to connect,int loop back up and wait for a new connection */
if (connd == -1) {
printf("failed to accept the connection..\n");
}
/* If it connects, read in and reply to the client */
else {
printf("Client connected successfully\n");
WOLFSSL* ssl;
if ( (ssl = wolfSSL_new(ctx)) == NULL) {
fprintf(stderr, "wolfSSL_new error.\n");
exit(EXIT_FAILURE);
}
/* direct our ssl to our clients connection */
wolfSSL_set_fd(ssl, connd);
printf("Using Non-Blocking I/O: %d\n", wolfSSL_get_using_nonblock(
ssl));
for ( ; ; ) {
char buff[256];
int ret = 0;
/* Clear the buffer memory for anything possibly left over */
memset(&buff, 0, sizeof(buff));
/* Read the client data into our buff array */
if ((ret = wolfSSL_read(ssl, buff, sizeof(buff)-1)) > 0) {
/* Print any data the client sends to the console */
printf("Client: %s\n", buff);
/* Reply back to the client */
if ((ret = wolfSSL_write(ssl, reply, sizeof(reply)-1))
< 0)
{
printf("wolfSSL_write error = %d\n", wolfSSL_get_error(ssl, ret));
}
}
/* if the client disconnects break the loop */
else {
if (ret < 0)
printf("wolfSSL_read error = %d\n", wolfSSL_get_error(ssl
,ret));
else if (ret == 0)
printf("The client has closed the connection.\n");
break;
}
}
wolfSSL_free(ssl); /* Free the WOLFSSL object */
}
close(connd); /* close the connected socket */
return 0;
}
int main()
{
/* Create a ctx pointer for our ssl */
WOLFSSL_CTX* ctx;
/*
* Creates a socket that uses an internet IP address,
* Sets the type to be Stream based (TCP),
* 0 means choose the default protocol.
*/
socklen_t sockfd = socket(AF_INET, SOCK_STREAM, 0);
int loopExit = 0; /* 0 = False, 1 = True */
int ret = 0; /* Return value */
/* Server and client socket address structures */
struct sockaddr_in serverAddr = {0}, clientAddr = {0};
/* Initialize wolfSSL */
wolfSSL_Init();
/* If positive value, the socket is valid */
if (sockfd == -1) {
printf("ERROR: failed to create the socket\n");
return EXIT_FAILURE; /* Kill the server with exit status 1 */
}
/* create and initialize WOLFSSL_CTX structure */
if ((ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method())) == NULL) {
fprintf(stderr, "wolfSSL_CTX_new error.\n");
return EXIT_FAILURE;
}
/* Load server certificate into WOLFSSL_CTX */
if (wolfSSL_CTX_use_certificate_file(ctx, "../certs/server-cert.pem",
SSL_FILETYPE_PEM) != SSL_SUCCESS) {
fprintf(stderr, "Error loading certs/server-cert.pem, please check"
"the file.\n");
return EXIT_FAILURE;
}
/* Load server key into WOLFSSL_CTX */
if (wolfSSL_CTX_use_PrivateKey_file(ctx, "../certs/server-key.pem",
SSL_FILETYPE_PEM) != SSL_SUCCESS) {
fprintf(stderr, "Error loading certs/server-key.pem, please check"
"the file.\n");
return EXIT_FAILURE;
}
/* load DH params */
ret = wolfSSL_CTX_SetTmpDH_file(ctx, "../certs/dh2048.pem" , SSL_FILETYPE_PEM);
if (ret != SSL_SUCCESS) {
fprintf(stderr, "Error setting DH parameters.\n");
return EXIT_FAILURE;
}
/* Initialize the server address struct to zero */
memset((char *)&serverAddr, 0, sizeof(serverAddr));
/* Fill the server's address family */
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(DEFAULT_PORT);
/* Attach the server socket to our port */
if (bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr))
< 0) {
printf("ERROR: failed to bind\n");
return EXIT_FAILURE;
}
printf("Waiting for a connection...\n");
/* Continuously accept connects while not currently in an active connection
or told to quit */
while (loopExit == 0) {
/* listen for a new connection, allow 5 pending connections */
ret = listen(sockfd, 5);
if (ret == 0) {
/* Accept client connections and read from them */
loopExit = AcceptAndRead(ctx, sockfd, clientAddr);
}
}
wolfSSL_CTX_free(ctx); /* Free WOLFSSL_CTX */
wolfSSL_Cleanup(); /* Free wolfSSL */
return EXIT_SUCCESS;
}
I would like to search Sat>IP servers on the network. Sat>IP servers advertise their presence to other Sat>IP servers and clients.
I must not continuosly send M-SEARCH messages but that instead it listens to server NOTIFY messages.
After initalizing network settings of my device, I'm sending M-SEARCH message and getting response if there is already any active Sat>IP server.
However, I couldn't get any response, If I opens Sat>IP server after sending M-SEARCH message.
Here's my code.
void SatIP::InitDiscoverThread()
{
if(INVALID_THREAD_CHK == DiscoverThreadChk)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, PTHREAD_STACK_SIZE);
printf("InitDiscoverThread pthread_create\n");
DiscoverThreadChk = PTH_RET_CHK(pthread_create(&DiscoverThreadID, &attr, DiscoverThreadFunc, this));
if(DiscoverThreadChk != 0)
{
ASSERT(0);
}
}
}
void SatIP::FinalizeDiscoverThread()
{
if(INVALID_THREAD_CHK != DiscoverThreadChk)
{
printf("FinalizeDiscoverThread pthread_cancel\n");
pthread_cancel(DiscoverThreadID);
DiscoverThreadChk = INVALID_THREAD_CHK;
close(discoverSocket);
}
}
void *SatIP::DiscoverThreadFunc(void* arg)
{
SatIP* satip = (SatIP *)arg;
satip->ListenSSDPResponse();
pthread_exit(NULL);
}
bool SatIP::SendMSearchMessage()
{
vSatIPServers.clear();
FinalizeDiscoverThread();
const char *searchSatIPDevice = "M-SEARCH * HTTP/1.1\r\n" \
"HOST: 239.255.255.250:1900\r\n" \
"MAN: \"ssdp:discover\"\r\n" \
"MX: 2\r\n" \
"ST: urn:ses-com:device:SatIPServer:1\r\n\r\n";
struct sockaddr_in upnpControl, broadcast_addr;
discoverSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (discoverSocket == INVALID_SOCKET)
{
printf("socked failed INVALID_SOCKET\n");
return false;
}
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
if(setsockopt(discoverSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)) == SOCKET_ERROR)
{
printf("setsockopt timeout failed\n");
close(discoverSocket);
return false;
}
socklen_t ttl = 2;
if(setsockopt(discoverSocket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == SOCKET_ERROR)
{
printf("setsockopt TTL failed\n");
close(discoverSocket);
return false;
}
if(setsockopt(discoverSocket, SOL_SOCKET, SO_BROADCAST, searchSatIPDevice, sizeof(searchSatIPDevice)) == SOCKET_ERROR)
{
printf("setsockopt broadcast failed\n");
close(discoverSocket);
return false;
}
upnpControl.sin_family = AF_INET;
upnpControl.sin_port = htons(0);
upnpControl.sin_addr.s_addr = INADDR_ANY;
if (bind(discoverSocket, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR)
{
printf("bind failed\n");
close(discoverSocket);
return false;
}
broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_port = htons(1900);
broadcast_addr.sin_addr.s_addr = inet_addr("239.255.255.250");
for(int i = 0; i < 3; i++)
{
if(sendto(discoverSocket, searchSatIPDevice, strlen(searchSatIPDevice), 0, (sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) == SOCKET_ERROR)
{
//printf("sendto failed\n");
close(discoverSocket);
return false;
}
else
{
usleep(10*100);
}
}
InitDiscoverThread();
return true;
}
void SatIP::ListenSSDPResponse()
{
while(1)
{
char buf[512];
memset(buf, 0, 512);
struct sockaddr_in broadcast_addr;
broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_port = htons(1900);
broadcast_addr.sin_addr.s_addr = inet_addr("239.255.255.250");
int bcLen = sizeof(broadcast_addr);
//bool bRet = false;
while (recvfrom(discoverSocket, buf, 512, 0, (struct sockaddr*)&broadcast_addr, (socklen_t*)&bcLen) > 0)
{
printf("buf:%s\n",buf);
SATIP_SERVER_DESCRIPTION stServerDesc;
ostringstream ss;
if(strstr(buf, "device:SatIPServer"))
{
int i = 0;
char *deviceIp = strstr(buf, "LOCATION:") + 9; // get xml location including server description
while(deviceIp[i] == ' ') i++; // remove spaces from string
while(!isspace(deviceIp[i]))
{
ss << deviceIp[i];
++i;
}
stServerDesc.location = ss.str().c_str();
printf("location:%s\n",stServerDesc.location.c_str());
ss.str(""); // clear ss
i=0; // clear counter
deviceIp = strstr(buf, "http://") + 7; // get ip address
while(deviceIp[i] != ':')
{
ss << deviceIp[i];
++i;
}
stServerDesc.ipAddr = ss.str().c_str();
printf("ipAddr:%s\n", stServerDesc.ipAddr.c_str());
DownloadDeviceDescription(&stServerDesc);
stServerDesc.macAddr = GetMACAddressviaIP(stServerDesc.ipAddr);
printf("macAddr:%s\n", stServerDesc.macAddr.c_str());
if(IsServerProperToAdd(&stServerDesc))
vSatIPServers.push_back(stServerDesc);
printf("\n");
//bRet = true;
}
memset(buf, 0, 512);
}
}
}
How can I fix this issue? Any help would be appreciated.
Listening SSDP notify message is not related to sending M-SEARCH message. Devices like Sat>IP send NOTIFY message to 239.255.255.250 periodically even if you don't send M-SEARCH message. So, you should join a multicast group and receives from the group.
You can use the listener program in the following link by changing HELLO_PORT as 1900 and HELLO_GROUP as "239.255.255.250".
http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/example.html
/*
* listener.c -- joins a multicast group and echoes all data it receives from
* the group to its stdout...
*
* Antony Courtney, 25/11/94
* Modified by: Frédéric Bastien (25/03/04)
* to compile without warning and work correctly
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define HELLO_PORT 1900
#define HELLO_GROUP "239.255.255.250"
#define MSGBUFSIZE 256
main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, nbytes,addrlen;
struct ip_mreq mreq;
char msgbuf[MSGBUFSIZE];
u_int yes=1; /*** MODIFICATION TO ORIGINAL */
/* create what looks like an ordinary UDP socket */
if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0) {
perror("socket");
exit(1);
}
/**** MODIFICATION TO ORIGINAL */
/* allow multiple sockets to use the same PORT number */
if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) < 0) {
perror("Reusing ADDR failed");
exit(1);
}
/*** END OF MODIFICATION TO ORIGINAL */
/* set up destination address */
memset(&addr,0,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY); /* N.B.: differs from sender */
addr.sin_port=htons(HELLO_PORT);
/* bind to receive address */
if (bind(fd,(struct sockaddr *) &addr,sizeof(addr)) < 0) {
perror("bind");
exit(1);
}
/* use setsockopt() to request that the kernel join a multicast group */
mreq.imr_multiaddr.s_addr=inet_addr(HELLO_GROUP);
mreq.imr_interface.s_addr=htonl(INADDR_ANY);
if (setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)) < 0) {
perror("setsockopt");
exit(1);
}
/* now just enter a read-print loop */
while (1) {
addrlen=sizeof(addr);
if ((nbytes=recvfrom(fd,msgbuf,MSGBUFSIZE,0,
(struct sockaddr *) &addr,&addrlen)) < 0) {
perror("recvfrom");
exit(1);
}
puts(msgbuf);
}
}
i'm doing a code for server client the server is CA and the client sends signed request to server and the server create signed certificate then the client sends to the server its certificate. The server first verify the certificate. also the client Extract the serial number of the certificate
i have some problems here
1- the verify process fail
verifiy fail
certificate signature failure
2- the serial number is always return a constant number 3 i don't know why
thx allot for helping me
certificate.cpp
#include <iostream>
#include "server.h"
#include "client.h"
using namespace std;
int main()
{
Client clientest;
Server servertest;
X509 *cert;
cert = servertest.CreateCertificate(clientest.MakeSignedCertReq());
clientest.SetCert(cert);
clientest.CertConverter();
X509 *test;
test = clientest.GetCert();
servertest.CheckCert(cert);
int serial = 0;
serial = clientest.ExtractCertSerial();
cout<<"client serial is "<<serial<<endl;
return 0;
}
server.h
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <openssl/asn1.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
#include <openssl/conf.h>
#include "client.h"
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
using namespace std;
class Server
{
public:
Server();
~Server();
X509 *CreateCertificate (X509_REQ *req);
void CreateMyCertificate();
void GenerateMyKeyPairs ( );
void SetPublicKey ();
int CheckCert (X509 *clientcert);
private:
X509 *m_myCert;
RSA *m_caKeyPairs;
EVP_PKEY *m_pukey;
X509_NAME *m_issuerName;
};
#endif /* SERVER_H_ */
server.cc
#include "server.h"
Server::Server()
{
m_myCert = X509_new();
m_caKeyPairs = RSA_new();
m_pukey = EVP_PKEY_new();
m_issuerName = X509_NAME_new();
GenerateMyKeyPairs();
CreateMyCertificate();
//SetPublicKey();
}
Server::~Server()
{
X509_free(m_myCert);
RSA_free(m_caKeyPairs);
X509_NAME_free(m_issuerName);
}
X509*
Server::CreateCertificate(X509_REQ* req)
{
cout<<"hello i began"<<endl;
X509 *m_req_reply;
m_req_reply = X509_new();
X509_NAME *subject = NULL;
EVP_PKEY *pkey = NULL;
ASN1_INTEGER_set(X509_get_serialNumber(m_req_reply), 2);
X509_gmtime_adj(X509_get_notBefore(m_req_reply), 0);
X509_gmtime_adj(X509_get_notAfter(m_req_reply), 31536000L);
pkey = X509_REQ_get_pubkey(req);
X509_set_pubkey(m_req_reply, pkey);
X509_NAME *issuerSubject = X509_get_subject_name(m_myCert);
X509_set_issuer_name(m_req_reply, issuerSubject);
//extract the subject of the request
subject = X509_REQ_get_subject_name(req);
X509_set_subject_name(m_req_reply, subject);
cout << "cert subject name:" << X509_get_subject_name(m_req_reply) << endl;
if(1 == X509_sign(m_req_reply, m_pukey, EVP_sha1()))
cout << "client cert ok\n";
else
cout << "client cert error\n";
return m_req_reply;
}
void
Server::CreateMyCertificate()
{
// we use rsa pairs and assign it into evp_key
SetPublicKey();
// properties of the certificate
//set the serial number
ASN1_INTEGER_set(X509_get_serialNumber(m_myCert), 1);
//set the time validity
X509_gmtime_adj(X509_get_notBefore(m_myCert), 0);
X509_gmtime_adj(X509_get_notAfter(m_myCert), 31536000L);
//set the public key of the cert to be signed
X509_set_pubkey(m_myCert, m_pukey);
//this is a self-signed certificate, we set the name of the issuer to the name of the subject
m_issuerName = X509_get_subject_name(m_myCert);
X509_NAME_add_entry_by_txt(m_issuerName, "C", MBSTRING_ASC,
(unsigned char *)"CA", -1, -1, 0);
X509_NAME_add_entry_by_txt(m_issuerName, "O", MBSTRING_ASC,
(unsigned char *)"MyCompany Inc.", -1, -1, 0);
X509_NAME_add_entry_by_txt(m_issuerName, "CN", MBSTRING_ASC,
(unsigned char *)"localhost", -1, -1, 0);
//set the issuer name
X509_set_issuer_name(m_myCert, m_issuerName);
//sign the cert
if(1 == X509_sign(m_myCert, m_pukey, EVP_sha1()))
cout << "self cert signed ok\n";
else
cout << "self cert sign error\n";
FILE * fcert;
fcert = fopen("cert.pem", "wb");
PEM_write_X509(
fcert, /* write the certificate to the file we've opened */
m_myCert /* our certificate */
);
}
void
Server::GenerateMyKeyPairs()
{
m_caKeyPairs = RSA_generate_key(2048,RSA_F4 , NULL , NULL);
}
void
Server::SetPublicKey()
{
if(1 == EVP_PKEY_assign_RSA(m_pukey,m_caKeyPairs))
cout << "key assigned OK\n";
else
cout << "key assign error\n";
BIO *out = NULL;
const char szPath[10] = "key2.pem";
out = BIO_new_file(szPath,"wb");
EVP_PKEY_print_private(out, m_pukey,
0, NULL);
BIO_free(out);
out = BIO_new_file("key.pem","wb");
//print the self signed certificate
//FILE * fkey;
//fkey = fopen("key.pem", "wb");
PEM_write_bio_PrivateKey(
out, /* write the key to the file we've opened */
m_pukey, /* our key from earlier */
EVP_des_ede3_cbc(), /* default cipher for encrypting the key on disk */
(unsigned char *)"replace_me", /* passphrase required for decrypting the key on disk */
10, /* length of the passphrase string */
NULL, /* callback for requesting a password */
NULL /* data to pass to the callback */
);
}
int
Server::CheckCert(X509* clientcert)
{
int status = 0;
X509_STORE_CTX *ctx = X509_STORE_CTX_new();
//void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx);
//void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
//store the trusted cert into ctx
X509_STORE *store = X509_STORE_new();
X509_STORE_add_cert(store, m_myCert);
//put the trusted cert and cert then verify it
X509_STORE_CTX_init(ctx,store, clientcert, NULL);
status = X509_verify_cert(ctx);
//status = X509_verify(clientcert, m_pukey);
if (status == 1)
{
cout<<"verified succesfully"<<endl;
}
else
{
cout<<"verifiy fail"<<endl;
cout << X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx));
}
return status;
}
client.h
#ifndef CLIENT_H_
#define CLIENT_H_
#include <stdlib.h>
#include <stdio.h>
#include <openssl/rsa.h>
#include <openssl/conf.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include "server.h"
class Client
{
public:
Client();
~Client();
void GenerateRSAKeyPair ();
void SetPublicKey ();
X509_REQ *MakeSignedCertReq();
void SetCert (X509 *cert);
X509 *GetCert();
int CertConverter ();
int ExtractCertSerial ();
private:
X509_REQ *m_myCertReq;
X509 *m_myCert;
X509_NAME *m_name;
RSA *m_rsa_keyPair;
EVP_PKEY *m_puk;
};
#endif /* CLIENT_H_ */
client.cc
#include "client.h"
Client :: Client()
{
m_myCertReq = X509_REQ_new();
m_myCert = X509_new();
m_name = X509_NAME_new();
m_rsa_keyPair = RSA_new();
m_puk = EVP_PKEY_new();
GenerateRSAKeyPair();
// SetPublicKey();
}
Client :: ~Client()
{
X509_REQ_free(m_myCertReq);
X509_free(m_myCert);
//X509_NAME_free(m_name);
RSA_free(m_rsa_keyPair);
//EVP_PKEY_free(m_puk);
}
void
Client :: GenerateRSAKeyPair ( )
{
m_rsa_keyPair = RSA_generate_key(2048,RSA_F4,NULL,NULL);
BIO *pubout = NULL;
const char szPath[10] = "clrsa.pem";
pubout = BIO_new_file(szPath,"wb");
PEM_write_bio_RSAPublicKey (pubout , m_rsa_keyPair);
}
void
Client::SetPublicKey()
{
EVP_PKEY_assign_RSA(m_puk,m_rsa_keyPair);
BIO *out = NULL;
const char szPath[10] = "cpuky.pem";
out = BIO_new_file(szPath,"wb");
PEM_write_bio_PUBKEY(out,m_puk);
}
X509_REQ*
Client::MakeSignedCertReq()
{
SetPublicKey();
//include the public key in the req
X509_REQ_set_pubkey(m_myCertReq,m_puk);
//set the subject name of the request
m_name=X509_REQ_get_subject_name(m_myCertReq);
//set the request
X509_NAME_add_entry_by_txt(m_name,"C",MBSTRING_ASC, (const unsigned char *)"UK", -1, -1, 0);
X509_NAME_add_entry_by_txt(m_name,"CN",MBSTRING_ASC, (const unsigned char *)"OpenSSL Group", -1, -1, 0);
//sign the req
X509_REQ_sign(m_myCertReq,m_puk,EVP_sha1());
BIO *out = NULL;
const char szPath[10] = "req.pem";
out = BIO_new_file(szPath,"wb");
PEM_write_bio_X509_REQ(out,m_myCertReq);
return m_myCertReq;
}
void
Client::SetCert(X509 *cert)
{
cout << "writing certificate\n";
BIO *out = NULL;
const char szPath[10] = "x509.pem";
out = BIO_new_file(szPath,"wb");
m_myCert = cert;
int len;
unsigned char *buf, *p;
len = i2d_X509(cert, NULL);
cout << "cert length =" << len << endl;
buf = (unsigned char *)OPENSSL_malloc(len);
p = buf;
i2d_X509(cert, &p);
cout << "cert= "<<endl;
for(int i=0; i<len; i++)
cout << buf[i];
cout << endl;
if(!PEM_write_bio_X509 (out , cert))
cout << "error writing certificate\n";
}
int
Client::CertConverter()
{
int len = i2d_X509(m_myCert, NULL);
unsigned char *buf, *p;
buf = (unsigned char *)OPENSSL_malloc(len);
p = buf;
i2d_X509(m_myCert, &p);
unsigned char certarray[len];
for (int i = 0 ; i<len ; i++)
{
certarray[i] = *(p-len+i);
}
cout << "converted client cert is"<<endl;
for (int j = 0 ; j<len ; j++)
{
cout << certarray[j];
}
cout<<endl;
/*
X509 *certtest = NULL;
certtest = d2i_X509(NULL, certarray , len);
cout<<"write the array to file"<<endl;
FILE * fcert;
fcert = fopen("certarray.pem", "wb");
PEM_write_X509(
fcert, //write the certificate to the file we've opened
certtest //our certificate
);
*/
return 0;
}
X509*
Client::GetCert()
{
return m_myCert;
}
int
Client::ExtractCertSerial()
{
int serial = 0;
unsigned char **out = NULL;
ASN1_INTEGER *asn1_serial = NULL;
asn1_serial = X509_get_serialNumber(m_myCert);
serial = i2d_ASN1_INTEGER(asn1_serial, out);
return (serial);
}
hope that any one can help me soon to solve my problem
note i have the self signed cert created well in cert.pem file also the x509.pem (for the client ) is created well but when i verify it i got an error all the time not verified because of the certificate signature failure when i got error handler X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)) also the serial number is always constant 3
I found out that in the request should add
//adds all digest algorithms to the table
OpenSSL_add_all_digests();
without this line the certificate will never be verified correctly
In CreateCertificate(X509_REQ* req){...}, you have
ASN1_INTEGER_set(X509_get_serialNumber(m_req_reply), 2); so you
will always set the serial number to 2(3).
Also in CreateCertificate(X509_REQ* req){...}, you haveif(1 == X509_sign(m_req_reply, m_pukey, EVP_sha1())) but X509_sign(...) will return the size of the signature instead of 1 if it succeeds.
i'm a beginner in network programming and i have a project in which i have to create a system explorer. That means that i will have the ability to write a http request with a directory in a browser and if the connection with the server is succesfull, the files from the above directory will open.
int main(int argc, char** argv)
{
typedef struct tcpip_connection
{
int connfd;
struct sockaddr_in peer_addr;
} tcpip_connection;
int s_socket, *fd, port;
char buffer[256];
struct sockaddr_in lis_addr;
struct sockaddr_in peer_addr;
int sopt = 1, n;
s_socket=socket(AF_INET, SOCK_STREAM, 0);
if(s_socket<0){
printf("error: the socket was not created!");
}
if(setsockopt(s_socket , SOL_SOCKET, SO_REUSEADDR, &sopt, sizeof(sopt))){
printf("Setsokopt error!");
}
memset(&lis_addr, 0, sizeof(lis_addr));
lis_addr.sin_family = AF_INET;
lis_addr.sin_addr.s_addr = htonl(INADDR_ANY);
lis_addr.sin_port = htons(port);
if ( bind( s_socket, (struct sockaddr*) &lis_addr, sizeof(lis_addr) ) < 0 ){
perror(NULL);
exit(-1);
}
if(listen(s_socket,15)<0){
perror("server.listen");
}
socklen_t peer_addrlen;
while(1){
if((fd = malloc(sizeof(int))) == NULL){
fprintf(stderr, "Out of memory\n");
abort();
}
*fd=accept(s_socket, (struct sockaddr*)&peer_addr,&peer_addrlen);
if(fd<0){
if( errno==EINTR /* Call interrupted by signal */
|| errno==ECONNABORTED /* connection was aborted */
|| errno==EMFILE /* per-process limit of open fds */
|| errno==ENFILE /* system-wide limit of open fds */
|| errno==ENOBUFS /* no space for socket buffers */
|| errno==ENOMEM /* no space for socket buffers */
|| errno==EPERM /* Firewall blocked the connection */
)
continue;
}
}
if(errno == EBADF)
break; /* return, the server_socket is closed */
}
bzero(buffer,1024);
n = read(*fd,buffer,1023);
if (n < 0)
{
perror("ERROR reading from socket");
exit(1);
}
printf("Here is the message: %s\n",buffer);
/* Write a response to the client
n = write(*fd,"I got your message",18);
if (n < 0)
{
perror("ERROR writing to socket");
exit(1);
}
return 0;*/
}
I don't know if there is anything wrong with my code, but the main problem is that i don't know how to make the browser connect with the server. Is there anything i have to write in the browser or do i have to add some extra code?
You forgot to initialize the port variable. Try setting port = 8080 before you call bind and listen.
Then, in your browser, go to http://localhost:8080/ and it should connect.
I'm trying to create an Apache module using socket to connect to the other server. It works well and I can retrieve data, but I have encountered three problems.
I can't keep connection with my server (auto close after each request).
I get 2 errors for each request in error log AH00052: child pid 7970 exit signal Segmentation fault (11).
When I continuously press f5 on my browser get error "No data received".
This is my module's code:
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/select.h>
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"
static int sockfd = -1;
static struct sockaddr_in saddr;
/* The sample content handler */
static int search_handler(request_rec *r)
{
r->content_type = "text/html";
ap_rprintf(r,"sockfd = %d<br>", sockfd);
if(sockfd == -1){
sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct hostent *server = gethostbyname("127.0.0.1");
if(server == NULL ) return DECLINED;
bzero((char *) &saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&saddr.sin_addr.s_addr,server->h_length);
saddr.sin_port = htons(9999);
if(sockfd == -1) return DECLINED;
if(connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){
ap_rputs("Can't connect.\n", r);
return OK;
}
}
send(sockfd, r->args, strlen(r->args), 0);
fd_set read_sd;
FD_ZERO(&read_sd);
FD_SET(sockfd, &read_sd);
int sel = select(sockfd + 1, &read_sd, 0, 0, 0);
if(sel < 0) {close(sockfd);return DECLINED;}
if( sel == 0) {ap_rprintf(r, "time out."); return OK;}
char buf[5000];
if(recv(sockfd, buf, 5000, 0) <= 0) return DECLINED;
ap_rprintf(r, "%s<br>%d", buf, sockfd);
return OK;
}
static void search_register_hooks(apr_pool_t *p)
{
ap_hook_handler(search_handler, NULL, NULL, APR_HOOK_LAST);
}
/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA search_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-dir config structures */
NULL, /* merge per-dir config structures */
NULL, /* create per-server config structures */
NULL, /* merge per-server config structures */
NULL, /* table of config file commands */
search_register_hooks /* register hooks */
};
How can I solve this?
Not a definite answer, but I believe you have to use apache pools for resource management in modules.