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