Blame test/test_ssl.c

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
}