-/* Copyright (C) 2009-2010, Martin Johansson <martin@fatbob.nu>
- Copyright (C) 2005-2010, Thorvald Natvig <thorvald@natvig.com>
+/* Copyright (C) 2009-2012, Martin Johansson <martin@fatbob.nu>
+ Copyright (C) 2005-2012, Thorvald Natvig <thorvald@natvig.com>
All rights reserved.
#include <polarssl/ssl.h>
#include <polarssl/net.h>
-#define CA_CRT_FILENAME "ca.crt"
-
+#ifdef POLARSSL_API_V1_2
+int ciphers[] =
+{
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ 0
+};
+#else
int ciphers[] =
{
SSL_EDH_RSA_AES_256_SHA,
- SSL_EDH_RSA_CAMELLIA_256_SHA,
- SSL_EDH_RSA_DES_168_SHA,
SSL_RSA_AES_256_SHA,
- SSL_RSA_CAMELLIA_256_SHA,
SSL_RSA_AES_128_SHA,
- SSL_RSA_CAMELLIA_128_SHA,
- SSL_RSA_DES_168_SHA,
- SSL_RSA_RC4_128_SHA,
- SSL_RSA_RC4_128_MD5,
0
};
+#endif
static x509_cert certificate;
static rsa_context key;
bool_t builtInTestCertificate;
havege_state hs; /* exported to crypt.c */
/* DH prime */
-const char *my_dhm_P =
+char *my_dhm_P =
"9CE85640903BF123906947FEDE767261" \
"D9B4A973EB8F7D984A8C656E2BCC161C" \
"183D4CA471BA78225F940F16D1D99CA3" \
"44FF6AB553EC7073AD0CB608F2A3B480" \
"19E6C02BCED40BD30E91BB2469089670" \
"DEF409C08E8AC24D1732A6128D2220DC53";
-const char *my_dhm_G = "4";
-
-const char *test_key =
- "-----BEGIN RSA PRIVATE KEY-----\r\n"
- "MIICXAIBAAKBgQC/zZ5p/st9JUgoFIuNCwyYJhKhnqKlAk36RJJAXhJ/3FZCThQK\r\n"
- "J0jxMCjnQb9envZPIKrAfyDtlEGKU8OI2HvDsFL7Y2fNjew0R9DoUyzPRVBInfW9\r\n"
- "JP03aiOldpooTjXBrzoZV+DGqRYJE/IRJEyXir5NEJu624bMJm0XDVkxiwIDAQAB\r\n"
- "AoGAPcFJiR01jYSsd+Mtj2sIUhCoHQuDmJdmXfcoE7t2P17FEzIqd55weN+lu9fK\r\n"
- "cv/BlHaTI8mK45PBinUv1ubE6gzzyLtNgBW7ko8i23YQNMS4+8ApZZoCFsVbN533\r\n"
- "/mFYcOmWpdgIsAOyi3gAyO5OyGA71a3gkNX+MDYc7PgbTkkCQQDq1NN/j6xVw4qc\r\n"
- "3qunsMOVJxln7Gkgt0fOrCV0WltJNkKYiARwtpvB/SHIj6nHhun+J/ee/v+QjAL4\r\n"
- "aUwC8OmnAkEA0RfWWVQ2Yxk9QjRcqcpDddtc+9xxM6Dt+edGDSYKRUB/S2cl/Sdg\r\n"
- "abFdrFEnFdO03VknCrqUgweegeUJhU1tfQJBAKLFFjxK59cijMejCDRZr5eI3HFO\r\n"
- "Sqgkoh8871Ew+ClM9OgpD3rY+CmEPZB5E+N7PmGublLEyXv1sHFi+w7m0e0CQDnH\r\n"
- "eoYIzVapHNJ0ob6Rk/63dYRrsCRyLhDGpgbwIhps7kAp6sd/4BaU2qvJaSGQ9QPN\r\n"
- "pQpD8NIcguKmJfFeKgkCQBABatS74xI2UAW/IIbRBg8a8z4v5JxEnQwp0EtmON2I\r\n"
- "+AVBenUVFjpdjaaQ2/2IEgEwnzRfbERQfUlAkjczRaM=\r\n"
- "-----END RSA PRIVATE KEY-----\r\n";
-
-const char *test_cert =
- "-----BEGIN CERTIFICATE-----\r\n"
- "MIICfDCCAeWgAwIBAgIJANEN9Jb9sp0oMA0GCSqGSIb3DQEBBQUAMFcxCzAJBgNV\r\n"
- "BAYTAlNFMRMwEQYDVQQHDApHb3RoZW5idXJnMRAwDgYDVQQKDAd1TXVybXVyMSEw\r\n"
- "HwYDVQQDDBh1TXVybXVyIHRlc3QgY2VydGlmaWNhdGUwHhcNMTEwMzIyMjIxMTEy\r\n"
- "WhcNMjEwMzE5MjIxMTEyWjBXMQswCQYDVQQGEwJTRTETMBEGA1UEBwwKR290aGVu\r\n"
- "YnVyZzEQMA4GA1UECgwHdU11cm11cjEhMB8GA1UEAwwYdU11cm11ciB0ZXN0IGNl\r\n"
- "cnRpZmljYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/zZ5p/st9JUgo\r\n"
- "FIuNCwyYJhKhnqKlAk36RJJAXhJ/3FZCThQKJ0jxMCjnQb9envZPIKrAfyDtlEGK\r\n"
- "U8OI2HvDsFL7Y2fNjew0R9DoUyzPRVBInfW9JP03aiOldpooTjXBrzoZV+DGqRYJ\r\n"
- "E/IRJEyXir5NEJu624bMJm0XDVkxiwIDAQABo1AwTjAdBgNVHQ4EFgQUyI0/J6gS\r\n"
- "G7vEZl1nKq9rAYAg/TMwHwYDVR0jBBgwFoAUyI0/J6gSG7vEZl1nKq9rAYAg/TMw\r\n"
- "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCGL3T4a7g+MUtcjIq2XLON\r\n"
- "cN/oPgPpMNcSPj7zQF1NVzjeQagvKIe3mL5sNIYuoIQm1Xm7aH2ueruhH0wkSOf0\r\n"
- "+7U/g7r70U1CFWzfgwzz3EWRq3hUQmZ9/Xy9V2P/iRrFNyAKE8MneuVv3aAIN6/W\r\n"
- "rWVxhCquqhFM3yIGe0f6hw==\r\n"
- "-----END CERTIFICATE-----\r\n";
-
+char *my_dhm_G = "4";
static void initTestCert()
{
int rc;
builtInTestCertificate = true;
- rc = x509parse_crt(&certificate, (unsigned char *)test_cert,
- strlen(test_cert));
- if (rc != 0)
- Log_fatal("Could not parse built-in test certificate");
- rc = x509parse_crt(&certificate, (unsigned char *)test_cert,
- strlen(test_cert));
+ rc = x509parse_crt(&certificate, (unsigned char *)test_srv_crt,
+ strlen(test_srv_crt));
if (rc != 0)
Log_fatal("Could not parse built-in test certificate");
}
{
int rc;
- rc = x509parse_key(&key, (unsigned char *)test_key,
- strlen(test_key), NULL, 0);
+ rc = x509parse_key(&key, (unsigned char *)test_srv_key,
+ strlen(test_srv_key), NULL, 0);
if (rc != 0)
Log_fatal("Could not parse built-in test RSA key");
}
/*
+ * How to generate a self-signed cert with openssl:
* openssl genrsa 1024 > host.key
* openssl req -new -x509 -nodes -sha1 -days 365 -key host.key > host.cert
*/
{
int rc;
char *crtfile = (char *)getStrConf(CERTIFICATE);
- char *ca_file, *p;
if (crtfile == NULL) {
Log_warn("No certificate file specified");
initTestCert();
return;
}
-
- /* Look for CA certificate file in same dir */
- ca_file = malloc(strlen(crtfile) + strlen(CA_CRT_FILENAME) + 1);
- strcpy(ca_file, crtfile);
- p = strrchr(ca_file, '/');
- if (p != NULL)
- strcpy(p + 1, CA_CRT_FILENAME);
- else
- strcpy(ca_file, CA_CRT_FILENAME);
-
- rc = x509parse_crtfile(&certificate, ca_file);
- if (rc != 0) { /* No CA certifiacte found. Assume self-signed. */
- Log_info("CA certificate file %s not found. Assuming self-signed certificate.", ca_file);
- }
-
- /*
- * PolarSSL 0.11 - 0.12,1 has a bug; it ignores the last certificate in the chain.
- * Read the certificate again so that it gets last in chain. Later releases like 0.14.0 works
- * fine with the extra certificate, so I don't see any harm in doing so.
- */
- rc = x509parse_crtfile(&certificate, crtfile);
- if (rc != 0)
- Log_fatal("Could not read certificate file %s", crtfile);
-
- free(ca_file);
}
static void initKey()
static void pssl_debug(void *ctx, int level, const char *str)
{
if (level <= DEBUG_LEVEL)
- Log_debug("PolarSSL [level %d]: %s", level, str);
+ Log_info("PolarSSL [level %d]: %s", level, str);
}
void SSLi_init(void)
{
+ char verstring[12];
+
initCert();
if (builtInTestCertificate) {
Log_warn("*** Using built-in test certificate and RSA key ***");
else
initKey();
havege_init(&hs);
+
+#ifdef POLARSSL_VERSION_MAJOR
+ version_get_string(verstring);
+ Log_info("PolarSSL library version %s initialized", verstring);
+#else
Log_info("PolarSSL library initialized");
+#endif
}
void SSLi_deinit(void)
rsa_free(&key);
}
+/* Create SHA1 of last certificate in the peer's chain. */
+bool_t SSLi_getSHA1Hash(SSL_handle_t *ssl, uint8_t *hash)
+{
+ x509_cert *cert;
+#ifdef POLARSSL_API_V1_2
+ cert = ssl_get_peer_cert(ssl);
+#else
+ cert = ssl->peer_cert;
+#endif
+ if (!cert) {
+ return false;
+ }
+ sha1(cert->raw.p, cert->raw.len, hash);
+ return true;
+}
+
SSL_handle_t *SSLi_newconnection(int *fd, bool_t *SSLready)
{
ssl_context *ssl;
Log_fatal("Failed to initalize: %d", rc);
ssl_set_endpoint(ssl, SSL_IS_SERVER);
- ssl_set_authmode(ssl, SSL_VERIFY_OPTIONAL);
+ ssl_set_authmode(ssl, SSL_VERIFY_OPTIONAL);
- ssl_set_rng(ssl, havege_rand, &hs);
- ssl_set_dbg(ssl, pssl_debug, NULL);
- ssl_set_bio(ssl, net_recv, fd, net_send, fd);
+ ssl_set_rng(ssl, HAVEGE_RAND, &hs);
+ ssl_set_dbg(ssl, pssl_debug, NULL);
+ ssl_set_bio(ssl, net_recv, fd, net_send, fd);
- ssl_set_ciphers(ssl, ciphers);
- ssl_set_session(ssl, 0, 0, ssn);
+#ifdef POLARSSL_API_V1
+ ssl_set_ciphersuites(ssl, ciphers);
+#else
+ ssl_set_ciphers(ssl, ciphers);
+#endif
- ssl_set_ca_chain(ssl, certificate.next, NULL, NULL);
- ssl_set_own_cert(ssl, &certificate, &key);
- ssl_set_dh_param(ssl, my_dhm_P, my_dhm_G);
+#ifdef POLARSSL_API_V1_2
+ ssl_set_session(ssl, ssn);
+#else
+ ssl_set_session(ssl, 0, 0, ssn);
+#endif
+
+ ssl_set_ca_chain(ssl, &certificate, NULL, NULL);
+ ssl_set_own_cert(ssl, &certificate, &key);
+ ssl_set_dh_param(ssl, my_dhm_P, my_dhm_G);
return ssl;
}
rc = ssl_handshake(ssl);
if (rc != 0) {
+#ifdef POLARSSL_API_V1
+ if (rc == POLARSSL_ERR_NET_WANT_READ || rc == POLARSSL_ERR_NET_WANT_WRITE) {
+#else
if (rc == POLARSSL_ERR_NET_TRY_AGAIN) {
+#endif
return 0;
+ } else if (POLARSSL_ERR_X509_CERT_VERIFY_FAILED) { /* Allow this (selfsigned etc) */
+ return 0;
} else {
Log_warn("SSL handshake failed: %d", rc);
return -1;
int SSLi_read(SSL_handle_t *ssl, uint8_t *buf, int len)
{
int rc;
+
rc = ssl_read(ssl, buf, len);
+#ifdef POLARSSL_API_V1
+ if (rc == POLARSSL_ERR_NET_WANT_READ)
+#else
if (rc == POLARSSL_ERR_NET_TRY_AGAIN)
+#endif
return SSLI_ERROR_WANT_READ;
return rc;
}
int SSLi_write(SSL_handle_t *ssl, uint8_t *buf, int len)
{
int rc;
+
rc = ssl_write(ssl, buf, len);
+#ifdef POLARSSL_API_V1
+ if (rc == POLARSSL_ERR_NET_WANT_WRITE)
+#else
if (rc == POLARSSL_ERR_NET_TRY_AGAIN)
+#endif
return SSLI_ERROR_WANT_WRITE;
return rc;
}
static RSA *rsa;
static SSL_CTX *context;
static EVP_PKEY *pkey;
+
+static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx);
static int SSL_add_ext(X509 * crt, int nid, char *value) {
X509_EXTENSION *ex;
{
const SSL_METHOD *method;
SSL *ssl;
- int i, offset = 0;
+ int i, offset = 0, cipherstringlen = 0;
STACK_OF(SSL_CIPHER) *cipherlist = NULL, *cipherlist_new = NULL;
SSL_CIPHER *cipher;
- char cipherstring[1024];
+ char *cipherstring, tempstring[128];
SSL_library_init();
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
}
Log_debug("List of ciphers:");
if (cipherlist_new) {
- for ( i = 0; (cipher = sk_SSL_CIPHER_value(cipherlist_new, i)) != NULL; i++) {
+ for (i = 0; (cipher = sk_SSL_CIPHER_value(cipherlist_new, i)) != NULL; i++) {
Log_debug("%s", SSL_CIPHER_get_name(cipher));
- offset += snprintf(cipherstring + offset, 1024 - offset, "%s:", SSL_CIPHER_get_name(cipher));
+ cipherstringlen += strlen(SSL_CIPHER_get_name(cipher)) + 1;
+ }
+ cipherstring = malloc(cipherstringlen + 1);
+ if (cipherstring == NULL)
+ Log_fatal("Out of memory");
+ for (i = 0; (cipher = sk_SSL_CIPHER_value(cipherlist_new, i)) != NULL; i++) {
+ offset += sprintf(cipherstring + offset, "%s:", SSL_CIPHER_get_name(cipher));
}
- cipherstring[offset - 1] = '\0';
}
if (cipherlist_new)
if (SSL_CTX_set_cipher_list(context, cipherstring) == 0)
Log_fatal("Failed to set cipher list!");
-
+
+ free(cipherstring);
+
+ SSL_CTX_set_verify(context, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
+ verify_callback);
SSL_free(ssl);
Log_info("OpenSSL library initialized");
return ssl;
}
+/* Create SHA1 of last certificate in the peer's chain. */
+bool_t SSLi_getSHA1Hash(SSL_handle_t *ssl, uint8_t *hash)
+{
+ X509 *x509;
+ uint8_t *buf, *p;
+ int len;
+
+ x509 = SSL_get_peer_certificate(ssl);
+ if (!x509) {
+ return false;
+ }
+
+ len = i2d_X509(x509, NULL);
+ buf = malloc(len);
+ if (buf == NULL) {
+ Log_fatal("malloc");
+ }
+
+ p = buf;
+ i2d_X509(x509, &p);
+
+ SHA1(buf, len, hash);
+ free(buf);
+ return true;
+}
+
void SSLi_closeconnection(SSL_handle_t *ssl)
{
SSL_free(ssl);
SSL_free(ssl);
}
+static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
+{
+ char buf[256];
+ X509 *err_cert;
+ int err, depth;
+ SSL *ssl;
+
+ err_cert = X509_STORE_CTX_get_current_cert(ctx);
+ err = X509_STORE_CTX_get_error(ctx);
+ depth = X509_STORE_CTX_get_error_depth(ctx);
+
+ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+ X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
+
+ if (depth > 5) {
+ preverify_ok = 0;
+ err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
+ X509_STORE_CTX_set_error(ctx, err);
+ }
+ if (!preverify_ok) {
+ Log_warn("SSL: verify error:num=%d:%s:depth=%d:%s\n", err,
+ X509_verify_cert_error_string(err), depth, buf);
+ }
+ /*
+ * At this point, err contains the last verification error. We can use
+ * it for something special
+ */
+ if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) {
+ X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
+ Log_warn("issuer= %s", buf);
+ }
+ return 1;
+}
+
#endif