summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2017-02-03 20:28:11 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2017-02-03 20:28:11 (GMT)
commit909007614922d1a23da894bc27696696d60c33ae (patch)
treee54d481cc8e24ccc83a010ef7017e49d48f3a0ca
Initial commit.HEADmaster
-rw-r--r--Makefile24
-rw-r--r--client.c112
-rw-r--r--common.h53
-rwxr-xr-xgen.sh277
-rw-r--r--server.c144
5 files changed, 610 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2e68f25
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,24 @@
+
+CFLAGS=$(shell pkg-config libssl --cflags)
+LDFLAGS=$(shell pkg-config libssl --libs)
+
+all: cacert.pem servercert.pem clientcert.pem client server
+
+cacert.pem:
+ ./gen.sh ca
+
+servercert.pem: cacert.pem
+ ./gen.sh server
+
+clientcert.pem: cacert.pem
+ ./gen.sh client
+
+server: server.c common.h
+ colorgcc -o server -Wall $(CFLAGS) server.c $(LDFLAGS)
+
+client: client.c common.h
+ colorgcc -o client -Wall $(CFLAGS) client.c $(LDFLAGS)
+
+clean:
+ rm -f server client *~
+ ./gen.sh clean
diff --git a/client.c b/client.c
new file mode 100644
index 0000000..666a519
--- /dev/null
+++ b/client.c
@@ -0,0 +1,112 @@
+
+#include <netdb.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+
+#include "common.h"
+
+
+int main(void)
+{
+ const SSL_METHOD *meth;
+ SSL_CTX *ctx;
+ int ret;
+ int sd;
+ struct sockaddr_in sa;
+ SSL *ssl;
+ X509 *server_cert;
+ char *str;
+ char buf[64];
+
+ /* Crypto */
+
+ SSL_load_error_strings();
+ OpenSSL_add_ssl_algorithms();
+
+ meth = TLSv1_2_client_method();
+ ctx = SSL_CTX_new(meth);
+ CHK_NULL(ctx);
+
+ ret = SSL_CTX_use_certificate_chain_file(ctx, "clientcert.pem");
+ CHK_SSL(ret);
+
+ ret = SSL_CTX_use_PrivateKey_file(ctx, "clientkey.pem", SSL_FILETYPE_PEM);
+ CHK_SSL(ret);
+
+ ret = SSL_CTX_check_private_key(ctx);
+ CHK_SSL(ret);
+
+ /* Networking */
+
+ sd = socket(AF_INET, SOCK_STREAM, 0);
+ CHK_ERR(sd, "socket");
+
+ memset(&sa, 0, sizeof(sa));
+
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = inet_addr("127.0.0.1");
+ sa.sin_port = htons(1111);
+
+ ret = connect(sd, (struct sockaddr *)&sa, sizeof(sa));
+ CHK_ERR(ret, "connect");
+
+ /* SSL negotiation. */
+
+ ssl = SSL_new(ctx);
+ CHK_NULL(ssl);
+
+ SSL_set_fd(ssl, sd);
+
+ ret = SSL_connect(ssl);
+ CHK_SSL_WRAPPER(ret);
+
+ /* Info */
+
+ printf("SSL connection using %s\n", SSL_get_cipher(ssl));
+
+ server_cert = SSL_get_peer_certificate(ssl);
+ CHK_NULL(server_cert);
+
+ printf("Server certificate:\n");
+
+ str = X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0);
+ CHK_NULL(str);
+ printf("\tsubject: %s\n", str);
+ OPENSSL_free(str);
+
+ str = X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0);
+ CHK_NULL(str);
+ printf("\tissuer: %s\n", str);
+ OPENSSL_free(str);
+
+ X509_free(server_cert);
+
+ /* Exchange */
+
+ ret = SSL_write(ssl, "Hello Server!", strlen("Hello Server!"));
+ CHK_SSL_WRAPPER(ret);
+
+ ret = SSL_read(ssl, buf, sizeof(buf) - 1);
+ CHK_SSL_WRAPPER(ret);
+
+ buf[ret] = '\0';
+
+ printf("Got %d chars: '%s'\n", ret, buf);
+
+ /* End */
+
+ SSL_shutdown(ssl);
+ close(sd);
+ SSL_free(ssl);
+ SSL_CTX_free(ctx);
+
+ return EXIT_SUCCESS;
+
+}
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..36d5c28
--- /dev/null
+++ b/common.h
@@ -0,0 +1,53 @@
+
+#ifndef _COMMON_H
+#define _COMMON_H
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <openssl/err.h>
+
+
+#define CHK_NULL(ptr) \
+ do \
+ { \
+ if ((ptr) == NULL) \
+ exit(1); \
+ } \
+ while (0)
+
+#define CHK_ERR(err, s) \
+ do \
+ { \
+ if ((err) == -1) \
+ { \
+ perror(s); \
+ exit(2); \
+ } \
+ } \
+ while (0)
+
+#define CHK_SSL(val) \
+ do \
+ { \
+ if ((val) == -1) \
+ { \
+ ERR_print_errors_fp(stderr); \
+ exit(3); \
+ } \
+ } \
+ while (0)
+
+#define CHK_SSL_WRAPPER(val) \
+ do \
+ { \
+ if ((val) == -1) \
+ { \
+ ERR_print_errors_fp(stderr); \
+ exit(3); \
+ } \
+ } \
+ while (0)
+
+
+#endif
diff --git a/gen.sh b/gen.sh
new file mode 100755
index 0000000..877eca3
--- /dev/null
+++ b/gen.sh
@@ -0,0 +1,277 @@
+#!/bin/bash
+
+# http://stackoverflow.com/questions/21297139/how-do-you-sign-certificate-signing-request-with-your-certification-authority
+
+
+function create_ca() {
+
+ cat > openssl-ca.cnf <<EOF
+HOME = .
+RANDFILE = .rnd
+
+####################################################################
+
+[ ca ]
+
+default_ca = CA_default # The default ca section
+
+[ CA_default ]
+
+default_days = 3650 # how long to certify for
+default_crl_days = 30 # how long before next CRL
+default_md = sha256 # use public key default MD
+preserve = no # keep passed DN ordering
+
+x509_extensions = ca_extensions # The extensions to add to the cert
+
+email_in_dn = no # Don't concat the email in the DN
+copy_extensions = copy # Required to copy SANs from CSR to cert
+
+certificate = cacert.pem # The CA certifcate
+private_key = cakey.pem # The CA private key
+new_certs_dir = . # Location for new certs after signing
+database = index.txt # Database index file
+serial = serial.txt # The current serial number
+
+unique_subject = no # Set to 'no' to allow creation of
+ # several certificates with same subject.
+
+####################################################################
+
+[ req ]
+
+default_bits = 4096
+default_keyfile = cakey.pem
+distinguished_name = ca_distinguished_name
+x509_extensions = ca_extensions
+string_mask = utf8only
+
+####################################################################
+
+[ ca_distinguished_name ]
+
+countryName = Country Name (2 letter code)
+countryName_default = FR
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = IDF
+
+localityName = Locality Name (eg, city)
+localityName_default = Paris
+
+organizationName = Organization Name (eg, company)
+organizationName_default = Fsociety
+
+organizationalUnitName = Organizational Unit (eg, division)
+organizationalUnitName_default = CA Research Department
+
+commonName = Common Name (e.g. server FQDN or YOUR name)
+commonName_default = Test CA
+
+emailAddress = Email Address
+emailAddress_default = ca@example.com
+
+####################################################################
+
+[ ca_extensions ]
+
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always, issuer
+basicConstraints = critical, CA:true
+keyUsage = keyCertSign, cRLSign
+
+[ signing_policy ]
+
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+####################################################################
+
+[ signing_req ]
+
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid, issuer
+
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature, keyEncipherment
+
+EOF
+
+ openssl req -x509 -config openssl-ca.cnf -newkey rsa:4096 -sha256 -nodes -keyout cakey.pem -out cacert.pem -outform PEM
+
+ if [ -f cacert.pem ]; then
+
+ ln -s cacert.pem `openssl x509 -hash -noout -in cacert.pem`.0
+
+ #openssl x509 -purpose -in cacert.pem -inform PEM | less
+
+ touch index.txt
+ echo '01' > serial.txt
+
+ fi
+
+}
+
+
+function create_server() {
+
+ cat > openssl-server.cnf <<EOF
+HOME = .
+RANDFILE = .rnd
+
+####################################################################
+
+[ req ]
+
+default_bits = 2048
+default_keyfile = serverkey.pem
+distinguished_name = server_distinguished_name
+req_extensions = server_req_extensions
+string_mask = utf8only
+
+####################################################################
+
+[ server_distinguished_name ]
+
+countryName = Country Name (2 letter code)
+countryName_default = FR
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = IDF
+
+localityName = Locality Name (eg, city)
+localityName_default = Paris
+
+organizationName = Organization Name (eg, company)
+organizationName_default = Server Organization
+
+organizationalUnitName = Organizational Unit (eg, division)
+organizationalUnitName_default = Server Research Department
+
+commonName = Common Name (e.g. server FQDN or YOUR name)
+commonName_default = ServerSide Test
+
+emailAddress = Email Address
+emailAddress_default = server@example.com
+
+####################################################################
+
+[ server_req_extensions ]
+
+subjectKeyIdentifier = hash
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature, keyEncipherment
+nsComment = "OpenSSL Generated Certificate"
+
+EOF
+
+ openssl req -config openssl-server.cnf -newkey rsa:2048 -sha256 -nodes -out serverkey.pem -outform PEM
+
+ # openssl req -text -noout -verify -in serverkey.pem | less
+
+ openssl ca -config openssl-ca.cnf -policy signing_policy -extensions signing_req -out servercert.pem -infiles serverkey.pem
+
+}
+
+
+function create_client() {
+
+ cat > openssl-client.cnf <<EOF
+HOME = .
+RANDFILE = .rnd
+
+####################################################################
+
+[ req ]
+
+default_bits = 2048
+default_keyfile = clientkey.pem
+distinguished_name = client_distinguished_name
+req_extensions = client_req_extensions
+string_mask = utf8only
+
+####################################################################
+
+[ client_distinguished_name ]
+
+countryName = Country Name (2 letter code)
+countryName_default = FR
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = IDF
+
+localityName = Locality Name (eg, city)
+localityName_default = Paris
+
+organizationName = Organization Name (eg, company)
+organizationName_default = Client Organization
+
+organizationalUnitName = Organizational Unit (eg, division)
+organizationalUnitName_default = Client Research Department
+
+commonName = Common Name (e.g. client FQDN or YOUR name)
+commonName_default = ClientSide Test
+
+emailAddress = Email Address
+emailAddress_default = client@example.com
+
+####################################################################
+
+[ client_req_extensions ]
+
+subjectKeyIdentifier = hash
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature, keyEncipherment
+nsComment = "OpenSSL Generated Certificate"
+
+EOF
+
+ openssl req -config openssl-client.cnf -newkey rsa:2048 -sha256 -nodes -out clientkey.pem -outform PEM
+
+ # openssl req -text -noout -verify -in clientkey.pem | less
+
+ openssl ca -config openssl-ca.cnf -policy signing_policy -extensions signing_req -out clientcert.pem -infiles clientkey.pem
+
+}
+
+
+function clean() {
+
+ rm -f .rnd
+
+ rm -f index.txt* serial.txt*
+
+ rm -f *.pem *.cnf *.0
+
+}
+
+
+case $1 in
+
+ ca)
+ create_ca
+ ;;
+
+ server)
+ create_server
+ ;;
+
+ client)
+ create_client
+ ;;
+
+ clean)
+ clean
+ ;;
+
+ *)
+ echo "Usage: $0 <ca|server|client|clean>"
+ exit 1
+ ;;
+
+esac
diff --git a/server.c b/server.c
new file mode 100644
index 0000000..da25676
--- /dev/null
+++ b/server.c
@@ -0,0 +1,144 @@
+
+#include <netdb.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <openssl/rsa.h>
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+
+#include "common.h"
+
+
+int main(void)
+{
+ const SSL_METHOD *meth;
+ SSL_CTX *ctx;
+ char cwd[256];
+ char *set;
+ int ret;
+ int listen_sd;
+ struct sockaddr_in sa_serv;
+ struct sockaddr_in sa_cli;
+ int sd;
+ SSL *ssl;
+ X509 *client_cert;
+ char *str;
+ char buf[64];
+
+ /* Crypto */
+
+ SSL_load_error_strings();
+ OpenSSL_add_ssl_algorithms();
+
+ meth = TLSv1_2_server_method();
+ ctx = SSL_CTX_new(meth);
+ CHK_NULL(ctx);
+
+ set = getcwd(cwd, sizeof(cwd));
+ CHK_NULL(set);
+
+ ret = SSL_CTX_load_verify_locations(ctx, "cacert.pem", cwd);
+ CHK_SSL(ret);
+
+ /*
+ ret = SSL_CTX_set_default_verify_paths(ctx);
+ CHK_SSL(ret);
+ */
+
+ SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file("cacert.pem"));
+
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
+
+ ret = SSL_CTX_use_certificate_chain_file(ctx, "servercert.pem");
+ CHK_SSL(ret);
+
+ ret = SSL_CTX_use_PrivateKey_file(ctx, "serverkey.pem", SSL_FILETYPE_PEM);
+ CHK_SSL(ret);
+
+ ret = SSL_CTX_check_private_key(ctx);
+ CHK_SSL(ret);
+
+ /* Networking */
+
+ listen_sd = socket(AF_INET, SOCK_STREAM, 0);
+ CHK_ERR(listen_sd, "socket");
+
+ memset(&sa_serv, 0, sizeof(sa_serv));
+
+ sa_serv.sin_family = AF_INET;
+ sa_serv.sin_addr.s_addr = INADDR_ANY;
+ sa_serv.sin_port = htons(1111);
+
+ ret = bind(listen_sd, (struct sockaddr *)&sa_serv, sizeof(sa_serv));
+ CHK_ERR(ret, "bind");
+
+ /* Waiting */
+
+ ret = listen(listen_sd, 5);
+ CHK_ERR(ret, "listen");
+
+ sd = accept(listen_sd, (struct sockaddr *)&sa_cli, (socklen_t []) { sizeof(sa_cli) });
+ CHK_ERR(sd, "accept");
+
+ close(listen_sd);
+
+ printf("Connection from %lx, port %hu\n", (unsigned long)sa_cli.sin_addr.s_addr, sa_cli.sin_port);
+
+ /* Server side SSL */
+
+ ssl = SSL_new(ctx);
+ CHK_NULL(ssl);
+
+ SSL_set_fd(ssl, sd);
+
+ ret = SSL_accept(ssl);
+ CHK_SSL(ret);
+
+ /* Info */
+
+ printf("SSL connection using %s\n", SSL_get_cipher(ssl));
+
+ client_cert = SSL_get_peer_certificate(ssl);
+ CHK_NULL(client_cert);
+
+ printf("Client certificate:\n");
+
+ str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
+ CHK_NULL(str);
+ printf("\tsubject: %s\n", str);
+ OPENSSL_free(str);
+
+ str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
+ CHK_NULL(str);
+ printf("\tissuer: %s\n", str);
+ OPENSSL_free(str);
+
+ X509_free(client_cert);
+
+ /* Exchange */
+
+ ret = SSL_write(ssl, "Hello Client!", strlen("Hello Client!"));
+ CHK_SSL_WRAPPER(ret);
+
+ ret = SSL_read(ssl, buf, sizeof(buf) - 1);
+ CHK_SSL_WRAPPER(ret);
+
+ buf[ret] = '\0';
+
+ printf("Got %d chars: '%s'\n", ret, buf);
+
+ /* End */
+
+ SSL_shutdown(ssl);
+ close(sd);
+ SSL_free(ssl);
+ SSL_CTX_free(ctx);
+
+ return EXIT_SUCCESS;
+
+}