|
Packit |
3adb1e |
/* ====================================================================
|
|
Packit |
3adb1e |
* Licensed to the Apache Software Foundation (ASF) under one
|
|
Packit |
3adb1e |
* or more contributor license agreements. See the NOTICE file
|
|
Packit |
3adb1e |
* distributed with this work for additional information
|
|
Packit |
3adb1e |
* regarding copyright ownership. The ASF licenses this file
|
|
Packit |
3adb1e |
* to you under the Apache License, Version 2.0 (the
|
|
Packit |
3adb1e |
* "License"); you may not use this file except in compliance
|
|
Packit |
3adb1e |
* with the License. You may obtain a copy of the License at
|
|
Packit |
3adb1e |
*
|
|
Packit |
3adb1e |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
3adb1e |
*
|
|
Packit |
3adb1e |
* Unless required by applicable law or agreed to in writing,
|
|
Packit |
3adb1e |
* software distributed under the License is distributed on an
|
|
Packit |
3adb1e |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
Packit |
3adb1e |
* KIND, either express or implied. See the License for the
|
|
Packit |
3adb1e |
* specific language governing permissions and limitations
|
|
Packit |
3adb1e |
* under the License.
|
|
Packit |
3adb1e |
* ====================================================================
|
|
Packit |
3adb1e |
*/
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include <apr.h>
|
|
Packit |
3adb1e |
#include <apr_pools.h>
|
|
Packit |
3adb1e |
#include <apr_strings.h>
|
|
Packit |
3adb1e |
#include <apr_env.h>
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include "serf.h"
|
|
Packit |
3adb1e |
#include "serf_bucket_types.h"
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include "test_serf.h"
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#if defined(WIN32) && defined(_DEBUG)
|
|
Packit |
3adb1e |
/* Include this file to allow running a Debug build of serf with a Release
|
|
Packit |
3adb1e |
build of OpenSSL. */
|
|
Packit |
3adb1e |
#include <openssl/applink.c>
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Test setting up the openssl library. */
|
|
Packit |
3adb1e |
static void test_ssl_init(CuTest *tc)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
serf_bucket_t *bkt, *stream;
|
|
Packit |
3adb1e |
serf_ssl_context_t *ssl_context;
|
|
Packit |
3adb1e |
apr_status_t status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_pool_t *test_pool = tc->testBaton;
|
|
Packit |
3adb1e |
serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
|
|
Packit |
3adb1e |
NULL);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
stream = SERF_BUCKET_SIMPLE_STRING("", alloc);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
bkt = serf_bucket_ssl_decrypt_create(stream, NULL,
|
|
Packit |
3adb1e |
alloc);
|
|
Packit |
3adb1e |
ssl_context = serf_bucket_ssl_decrypt_context_get(bkt);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
bkt = serf_bucket_ssl_encrypt_create(stream, ssl_context,
|
|
Packit |
3adb1e |
alloc);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = serf_ssl_use_default_certificates(ssl_context);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuAssertIntEquals(tc, APR_SUCCESS, status);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#define get_ca_file(pool, file) get_srcdir_file(pool, file)
|
|
Packit |
3adb1e |
/* Test that loading a custom CA certificate file works. */
|
|
Packit |
3adb1e |
static void test_ssl_load_cert_file(CuTest *tc)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
serf_ssl_certificate_t *cert = NULL;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_pool_t *test_pool = tc->testBaton;
|
|
Packit |
3adb1e |
apr_status_t status = serf_ssl_load_cert_file(
|
|
Packit |
3adb1e |
&cert, get_ca_file(test_pool, "test/serftestca.pem"), test_pool);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuAssertIntEquals(tc, APR_SUCCESS, status);
|
|
Packit |
3adb1e |
CuAssertPtrNotNull(tc, cert);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Test that reading the subject from a custom CA certificate file works. */
|
|
Packit |
3adb1e |
static void test_ssl_cert_subject(CuTest *tc)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
apr_hash_t *subject;
|
|
Packit |
3adb1e |
serf_ssl_certificate_t *cert = NULL;
|
|
Packit |
3adb1e |
apr_status_t status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_pool_t *test_pool = tc->testBaton;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = serf_ssl_load_cert_file(&cert, get_ca_file(test_pool,
|
|
Packit |
3adb1e |
"test/serftestca.pem"),
|
|
Packit |
3adb1e |
test_pool);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuAssertIntEquals(tc, APR_SUCCESS, status);
|
|
Packit |
3adb1e |
CuAssertPtrNotNull(tc, cert);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
subject = serf_ssl_cert_subject(cert, test_pool);
|
|
Packit |
3adb1e |
CuAssertPtrNotNull(tc, subject);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "Serf",
|
|
Packit |
3adb1e |
apr_hash_get(subject, "CN", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "Test Suite",
|
|
Packit |
3adb1e |
apr_hash_get(subject, "OU", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "In Serf we trust, Inc.",
|
|
Packit |
3adb1e |
apr_hash_get(subject, "O", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "Mechelen",
|
|
Packit |
3adb1e |
apr_hash_get(subject, "L", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "Antwerp",
|
|
Packit |
3adb1e |
apr_hash_get(subject, "ST", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "BE",
|
|
Packit |
3adb1e |
apr_hash_get(subject, "C", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "serf@example.com",
|
|
Packit |
3adb1e |
apr_hash_get(subject, "E", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Test that reading the issuer from a custom CA certificate file works. */
|
|
Packit |
3adb1e |
static void test_ssl_cert_issuer(CuTest *tc)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
apr_hash_t *issuer;
|
|
Packit |
3adb1e |
serf_ssl_certificate_t *cert = NULL;
|
|
Packit |
3adb1e |
apr_status_t status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_pool_t *test_pool = tc->testBaton;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = serf_ssl_load_cert_file(&cert, get_ca_file(test_pool,
|
|
Packit |
3adb1e |
"test/serftestca.pem"),
|
|
Packit |
3adb1e |
test_pool);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuAssertIntEquals(tc, APR_SUCCESS, status);
|
|
Packit |
3adb1e |
CuAssertPtrNotNull(tc, cert);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
issuer = serf_ssl_cert_issuer(cert, test_pool);
|
|
Packit |
3adb1e |
CuAssertPtrNotNull(tc, issuer);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* TODO: create a new test certificate with different issuer and subject. */
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "Serf",
|
|
Packit |
3adb1e |
apr_hash_get(issuer, "CN", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "Test Suite",
|
|
Packit |
3adb1e |
apr_hash_get(issuer, "OU", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "In Serf we trust, Inc.",
|
|
Packit |
3adb1e |
apr_hash_get(issuer, "O", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "Mechelen",
|
|
Packit |
3adb1e |
apr_hash_get(issuer, "L", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "Antwerp",
|
|
Packit |
3adb1e |
apr_hash_get(issuer, "ST", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "BE",
|
|
Packit |
3adb1e |
apr_hash_get(issuer, "C", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "serf@example.com",
|
|
Packit |
3adb1e |
apr_hash_get(issuer, "E", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Test that reading the notBefore,notAfter,sha1 fingerprint and subjectAltNames
|
|
Packit |
3adb1e |
from a custom CA certificate file works. */
|
|
Packit |
3adb1e |
static void test_ssl_cert_certificate(CuTest *tc)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
apr_hash_t *kv;
|
|
Packit |
3adb1e |
serf_ssl_certificate_t *cert = NULL;
|
|
Packit |
3adb1e |
apr_array_header_t *san_arr;
|
|
Packit |
3adb1e |
apr_status_t status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_pool_t *test_pool = tc->testBaton;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = serf_ssl_load_cert_file(&cert, get_ca_file(test_pool,
|
|
Packit |
3adb1e |
"test/serftestca.pem"),
|
|
Packit |
3adb1e |
test_pool);
|
|
Packit |
3adb1e |
CuAssertIntEquals(tc, APR_SUCCESS, status);
|
|
Packit |
3adb1e |
CuAssertPtrNotNull(tc, cert);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
kv = serf_ssl_cert_certificate(cert, test_pool);
|
|
Packit |
3adb1e |
CuAssertPtrNotNull(tc, kv);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "8A:4C:19:D5:F2:52:4E:35:49:5E:7A:14:80:B2:02:BD:B4:4D:22:18",
|
|
Packit |
3adb1e |
apr_hash_get(kv, "sha1", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "Mar 21 13:18:17 2008 GMT",
|
|
Packit |
3adb1e |
apr_hash_get(kv, "notBefore", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, "Mar 21 13:18:17 2011 GMT",
|
|
Packit |
3adb1e |
apr_hash_get(kv, "notAfter", APR_HASH_KEY_STRING));
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* TODO: create a new test certificate with a/some sAN's. */
|
|
Packit |
3adb1e |
san_arr = apr_hash_get(kv, "subjectAltName", APR_HASH_KEY_STRING);
|
|
Packit |
3adb1e |
CuAssertTrue(tc, san_arr == NULL);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static const char *extract_cert_from_pem(const char *pemdata,
|
|
Packit |
3adb1e |
apr_pool_t *pool)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
enum { INIT, CERT_BEGIN, CERT_FOUND } state;
|
|
Packit |
3adb1e |
serf_bucket_t *pembkt;
|
|
Packit |
3adb1e |
const char *begincert = "-----BEGIN CERTIFICATE-----";
|
|
Packit |
3adb1e |
const char *endcert = "-----END CERTIFICATE-----";
|
|
Packit |
3adb1e |
char *certdata = "";
|
|
Packit |
3adb1e |
apr_size_t certlen = 0;
|
|
Packit |
3adb1e |
apr_status_t status = APR_SUCCESS;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(pool,
|
|
Packit |
3adb1e |
NULL, NULL);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Extract the certificate from the .pem file, also remove newlines. */
|
|
Packit |
3adb1e |
pembkt = SERF_BUCKET_SIMPLE_STRING(pemdata, alloc);
|
|
Packit |
3adb1e |
state = INIT;
|
|
Packit |
3adb1e |
while (state != CERT_FOUND && status != APR_EOF) {
|
|
Packit |
3adb1e |
const char *data;
|
|
Packit |
3adb1e |
apr_size_t len;
|
|
Packit |
3adb1e |
int found;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = serf_bucket_readline(pembkt, SERF_NEWLINE_ANY, &found,
|
|
Packit |
3adb1e |
&data, &len;;
|
|
Packit |
3adb1e |
if (SERF_BUCKET_READ_ERROR(status))
|
|
Packit |
3adb1e |
return NULL;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (state == INIT) {
|
|
Packit |
3adb1e |
if (strncmp(begincert, data, strlen(begincert)) == 0)
|
|
Packit |
3adb1e |
state = CERT_BEGIN;
|
|
Packit |
3adb1e |
} else if (state == CERT_BEGIN) {
|
|
Packit |
3adb1e |
if (strncmp(endcert, data, strlen(endcert)) == 0)
|
|
Packit |
3adb1e |
state = CERT_FOUND;
|
|
Packit |
3adb1e |
else {
|
|
Packit |
3adb1e |
certdata = apr_pstrcat(pool, certdata, data, NULL);
|
|
Packit |
3adb1e |
certlen += len;
|
|
Packit |
3adb1e |
switch (found) {
|
|
Packit |
3adb1e |
case SERF_NEWLINE_CR:
|
|
Packit |
3adb1e |
case SERF_NEWLINE_LF:
|
|
Packit |
3adb1e |
certdata[certlen-1] = '\0';
|
|
Packit |
3adb1e |
certlen --;
|
|
Packit |
3adb1e |
break;
|
|
Packit |
3adb1e |
case SERF_NEWLINE_CRLF:
|
|
Packit |
3adb1e |
certdata[certlen-2] = '\0';
|
|
Packit |
3adb1e |
certlen-=2;
|
|
Packit |
3adb1e |
break;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (state == CERT_FOUND)
|
|
Packit |
3adb1e |
return certdata;
|
|
Packit |
3adb1e |
else
|
|
Packit |
3adb1e |
return NULL;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static void test_ssl_cert_export(CuTest *tc)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
serf_ssl_certificate_t *cert = NULL;
|
|
Packit |
3adb1e |
apr_file_t *fp;
|
|
Packit |
3adb1e |
apr_finfo_t file_info;
|
|
Packit |
3adb1e |
const char *base64derbuf;
|
|
Packit |
3adb1e |
char *pembuf;
|
|
Packit |
3adb1e |
apr_size_t pemlen;
|
|
Packit |
3adb1e |
apr_status_t status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_pool_t *test_pool = tc->testBaton;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = serf_ssl_load_cert_file(&cert, get_ca_file(test_pool,
|
|
Packit |
3adb1e |
"test/serftestca.pem"),
|
|
Packit |
3adb1e |
test_pool);
|
|
Packit |
3adb1e |
CuAssertIntEquals(tc, APR_SUCCESS, status);
|
|
Packit |
3adb1e |
CuAssertPtrNotNull(tc, cert);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* A .pem file contains a Base64 encoded DER certificate, which is exactly
|
|
Packit |
3adb1e |
what serf_ssl_cert_export is supposed to be returning. */
|
|
Packit |
3adb1e |
status = apr_file_open(&fp,
|
|
Packit |
3adb1e |
get_srcdir_file(test_pool, "test/serftestca.pem"),
|
|
Packit |
3adb1e |
APR_FOPEN_READ | APR_FOPEN_BINARY,
|
|
Packit |
3adb1e |
APR_FPROT_OS_DEFAULT, test_pool);
|
|
Packit |
3adb1e |
CuAssertIntEquals(tc, APR_SUCCESS, status);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_file_info_get(&file_info, APR_FINFO_SIZE, fp);
|
|
Packit |
3adb1e |
pembuf = apr_palloc(test_pool, file_info.size);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = apr_file_read_full(fp, pembuf, file_info.size, &pemlen);
|
|
Packit |
3adb1e |
CuAssertIntEquals(tc, APR_SUCCESS, status);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
base64derbuf = serf_ssl_cert_export(cert, test_pool);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc,
|
|
Packit |
3adb1e |
extract_cert_from_pem(pembuf, test_pool),
|
|
Packit |
3adb1e |
base64derbuf);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuSuite *test_ssl(void)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
CuSuite *suite = CuSuiteNew();
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuSuiteSetSetupTeardownCallbacks(suite, test_setup, test_teardown);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
SUITE_ADD_TEST(suite, test_ssl_init);
|
|
Packit |
3adb1e |
SUITE_ADD_TEST(suite, test_ssl_load_cert_file);
|
|
Packit |
3adb1e |
SUITE_ADD_TEST(suite, test_ssl_cert_subject);
|
|
Packit |
3adb1e |
SUITE_ADD_TEST(suite, test_ssl_cert_issuer);
|
|
Packit |
3adb1e |
SUITE_ADD_TEST(suite, test_ssl_cert_certificate);
|
|
Packit |
3adb1e |
SUITE_ADD_TEST(suite, test_ssl_cert_export);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return suite;
|
|
Packit |
3adb1e |
}
|