113 lines
2.9 KiB
C
113 lines
2.9 KiB
C
// heavily copypasted from http://www.rtfm.com/openssl-examples/
|
|
#include <openssl/err.h>
|
|
#include <openssl/ssl.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <netinet/in.h>
|
|
#include <netdb.h>
|
|
#include <unistd.h>
|
|
#include "config.h"
|
|
size_t strnlen(const char *s, size_t maxlen);
|
|
|
|
static char id_ctx[] = "hackfridge-ssl-context";
|
|
int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata) {
|
|
strncpy(buf, userdata, size);
|
|
return strlen(userdata);
|
|
}
|
|
|
|
int initialize_ctx(const char* chainfile, const char* keyfile, const char* password,
|
|
const char* ca_file, SSL_CTX** rctx)
|
|
{
|
|
const SSL_METHOD *meth;
|
|
SSL_CTX* ctx;
|
|
int result = 1;
|
|
|
|
/* Create our context*/
|
|
meth=TLSv1_client_method();
|
|
ctx=SSL_CTX_new(meth);
|
|
if (!ctx)
|
|
{
|
|
ERR_print_errors_fp(stderr);
|
|
return -1;
|
|
}
|
|
|
|
/* Load our keys and certificates*/
|
|
result = SSL_CTX_use_certificate_chain_file(ctx, chainfile);
|
|
if(!result) goto exit;
|
|
|
|
SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
|
|
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void*) password);
|
|
result = SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM);
|
|
if(!result) goto finalize;
|
|
|
|
/* Load the CAs we trust*/
|
|
result = SSL_CTX_load_verify_locations(ctx, ca_file,0);
|
|
if(!result) goto finalize;
|
|
goto exit;
|
|
finalize:
|
|
SSL_CTX_free(ctx);
|
|
exit:
|
|
*rctx = ctx;
|
|
return result;
|
|
}
|
|
|
|
int send_purchase(const char* host, int port, const char* code, const char* dn) {
|
|
SSL_CTX* ctx;
|
|
BIO* bio;
|
|
SSL* ssl;
|
|
int result, sock, conn;
|
|
char msg[200];
|
|
*msg = 0;
|
|
result = initialize_ctx(SSL_CERT, SSL_CERT_KEY, SSL_PASSWORD, CA_FILE, &ctx);
|
|
if(!result) return result; // :(
|
|
SSL_CTX_set_session_id_context(ctx, id_ctx, sizeof id_ctx);
|
|
|
|
struct sockaddr_in addr;
|
|
memset(&addr, 0, sizeof(addr));
|
|
struct hostent *hp;
|
|
if(!(hp = gethostbyname(host))) {
|
|
result = -2;
|
|
goto finalize;
|
|
}
|
|
addr.sin_addr = *(struct in_addr*)hp->h_addr_list[0];
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = htons(port);
|
|
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
result = -3;
|
|
if(sock < 0) goto finalize;
|
|
result = connect(sock, (struct sockaddr*) &addr, sizeof(addr));
|
|
if(result < 0) goto close_socket;
|
|
|
|
ssl = SSL_new(ctx);
|
|
bio = BIO_new_socket(sock, BIO_NOCLOSE);
|
|
if(!bio) {
|
|
result = -4;
|
|
goto free_ssl;
|
|
}
|
|
SSL_set_bio(ssl, bio, bio);
|
|
result = SSL_connect(ssl);
|
|
if(result < 0) goto free_ssl;
|
|
|
|
strncat(msg, code, 200);
|
|
strncat(msg, " ", 200);
|
|
strncat(msg, dn, 200);
|
|
strncat(msg, "\n", 200);
|
|
int pending = strnlen(msg, 200);
|
|
char* t_msg = msg;
|
|
while(pending > 0) {
|
|
result = SSL_write(ssl, t_msg, pending);
|
|
if(result == 0) result = SSL_get_error(ssl, result); // :(
|
|
if(result < 0) goto free_ssl;
|
|
pending -= result;
|
|
t_msg += result;
|
|
}
|
|
SSL_shutdown(ssl);
|
|
free_ssl:
|
|
SSL_free(ssl);
|
|
close_socket:
|
|
close(sock);
|
|
finalize:
|
|
SSL_CTX_free(ctx);
|
|
return result;
|
|
}
|