1189251Ssam/* Licensed to the Apache Software Foundation (ASF) under one or more 2189251Ssam * contributor license agreements. See the NOTICE file distributed with 3189251Ssam * this work for additional information regarding copyright ownership. 4189251Ssam * The ASF licenses this file to You under the Apache License, Version 2.0 5252726Srpaulo * (the "License"); you may not use this file except in compliance with 6252726Srpaulo * the License. You may obtain a copy of the License at 7189251Ssam * 8189251Ssam * http://www.apache.org/licenses/LICENSE-2.0 9189251Ssam * 10189251Ssam * Unless required by applicable law or agreed to in writing, software 11189251Ssam * distributed under the License is distributed on an "AS IS" BASIS, 12189251Ssam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13189251Ssam * See the License for the specific language governing permissions and 14189251Ssam * limitations under the License. 15189251Ssam */ 16189251Ssam 17189251Ssam#include <assert.h> 18189251Ssam#include <stdio.h> 19189251Ssam#include <stdlib.h> 20189251Ssam 21189251Ssam#include "apr_errno.h" 22189251Ssam#include "apr_strings.h" 23189251Ssam#include "apr_file_io.h" 24189251Ssam#include "apr_thread_pool.h" 25189251Ssam#include "apr_md5.h" 26189251Ssam#include "apr_sha1.h" 27189251Ssam 28189251Ssam#include "abts.h" 29189251Ssam#include "testutil.h" 30189251Ssam 31189251Ssam#if defined(WIN32) || defined(BEOS) || defined(NETWARE) 32189251Ssam#define CRYPT_ALGO_SUPPORTED 0 33189251Ssam#else 34189251Ssam#define CRYPT_ALGO_SUPPORTED 1 35189251Ssam#endif 36189251Ssam 37189251Ssam#if defined __GLIBC_PREREQ 38189251Ssam#if __GLIBC_PREREQ(2,7) 39189251Ssam#define GLIBCSHA_ALGO_SUPPORTED 40189251Ssam#endif 41189251Ssam#endif 42189251Ssam 43189251Ssam#if CRYPT_ALGO_SUPPORTED 44189251Ssam 45189251Ssamstatic struct { 46189251Ssam const char *password; 47189251Ssam const char *hash; 48189251Ssam} passwords[] = 49189251Ssam{ 50189251Ssam/* 51189251Ssam passwords and hashes created with Apache's htpasswd utility like this: 52189251Ssam 53189251Ssam htpasswd -c -b passwords pass1 pass1 54189251Ssam htpasswd -b passwords pass2 pass2 55189251Ssam htpasswd -b passwords pass3 pass3 56189251Ssam htpasswd -b passwords pass4 pass4 57189251Ssam htpasswd -b passwords pass5 pass5 58189251Ssam htpasswd -b passwords pass6 pass6 59189251Ssam htpasswd -b passwords pass7 pass7 60189251Ssam htpasswd -b passwords pass8 pass8 61189251Ssam (insert Perl one-liner to convert to initializer :) ) 62189251Ssam */ 63189251Ssam {"pass1", "1fWDc9QWYCWrQ"}, 64189251Ssam {"pass2", "1fiGx3u7QoXaM"}, 65189251Ssam {"pass3", "1fzijMylTiwCs"}, 66189251Ssam {"pass4", "nHUYc8U2UOP7s"}, 67252726Srpaulo {"pass5", "nHpETGLGPwAmA"}, 68252726Srpaulo {"pass6", "nHbsbWmJ3uyhc"}, 69252726Srpaulo {"pass7", "nHQ3BbF0Y9vpI"}, 70252726Srpaulo {"pass8", "nHZA1rViSldQk"} 71252726Srpaulo}; 72252726Srpaulostatic int num_passwords = sizeof(passwords) / sizeof(passwords[0]); 73252726Srpaulo 74252726Srpaulostatic void test_crypt(abts_case *tc, void *data) 75252726Srpaulo{ 76252726Srpaulo int i; 77252726Srpaulo 78252726Srpaulo for (i = 0; i < num_passwords; i++) { 79252726Srpaulo apr_assert_success(tc, "check for valid password", 80252726Srpaulo apr_password_validate(passwords[i].password, 81252726Srpaulo passwords[i].hash)); 82252726Srpaulo } 83252726Srpaulo} 84252726Srpaulo 85189251Ssam#if APR_HAS_THREADS 86189251Ssam 87189251Ssamstatic void * APR_THREAD_FUNC testing_thread(apr_thread_t *thd, 88189251Ssam void *data) 89189251Ssam{ 90189251Ssam abts_case *tc = data; 91189251Ssam int i; 92189251Ssam 93189251Ssam for (i = 0; i < 100; i++) { 94189251Ssam test_crypt(tc, NULL); 95189251Ssam } 96189251Ssam 97189251Ssam return APR_SUCCESS; 98189251Ssam} 99189251Ssam 100189251Ssam#define NUM_THR 20 101189251Ssam 102189251Ssam/* test for threadsafe crypt() */ 103189251Ssamstatic void test_threadsafe(abts_case *tc, void *data) 104189251Ssam{ 105189251Ssam int i; 106189251Ssam apr_status_t rv; 107189251Ssam apr_thread_pool_t *thrp; 108189251Ssam 109189251Ssam rv = apr_thread_pool_create(&thrp, NUM_THR/2, NUM_THR, p); 110189251Ssam ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 111189251Ssam 112189251Ssam for (i = 0; i < NUM_THR; i++) { 113189251Ssam rv = apr_thread_pool_push(thrp, testing_thread, tc, 0, NULL); 114189251Ssam ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); 115189251Ssam } 116189251Ssam 117189251Ssam apr_thread_pool_destroy(thrp); 118189251Ssam} 119189251Ssam#endif 120189251Ssam 121189251Ssam#endif /* CRYPT_ALGO_SUPPORTED */ 122189251Ssam 123189251Ssamstatic void test_shapass(abts_case *tc, void *data) 124189251Ssam{ 125189251Ssam const char *pass = "hellojed"; 126189251Ssam const char *pass2 = "hellojed2"; 127189251Ssam char hash[100]; 128189251Ssam 129189251Ssam apr_sha1_base64(pass, strlen(pass), hash); 130189251Ssam 131189251Ssam apr_assert_success(tc, "SHA1 password validated", 132189251Ssam apr_password_validate(pass, hash)); 133189251Ssam APR_ASSERT_FAILURE(tc, "wrong SHA1 password should not validate", 134189251Ssam apr_password_validate(pass2, hash)); 135189251Ssam} 136189251Ssam 137189251Ssamstatic void test_md5pass(abts_case *tc, void *data) 138189251Ssam{ 139189251Ssam const char *pass = "hellojed", *salt = "sardine"; 140189251Ssam const char *pass2 = "hellojed2"; 141189251Ssam char hash[100]; 142189251Ssam 143189251Ssam apr_md5_encode(pass, salt, hash, sizeof hash); 144189251Ssam 145189251Ssam apr_assert_success(tc, "MD5 password validated", 146189251Ssam apr_password_validate(pass, hash)); 147189251Ssam APR_ASSERT_FAILURE(tc, "wrong MD5 password should not validate", 148189251Ssam apr_password_validate(pass2, hash)); 149189251Ssam} 150189251Ssam 151189251Ssam#ifdef GLIBCSHA_ALGO_SUPPORTED 152189251Ssam 153189251Ssamstatic struct { 154189251Ssam const char *password; 155189251Ssam const char *hash; 156189251Ssam} glibc_sha_pws[] = { 157189251Ssam /* SHA256 */ 158189251Ssam { "secret1", "$5$0123456789abcdef$SFX.CooXBS8oXsbAPgU/UyiCodhrLQ19sBgvcA3Zh1D" }, 159189251Ssam { "secret2", "$5$rounds=100000$0123456789abcdef$dLXfO5m4d.xv8G66kpz2LyL0.Mi5wjLlH0m7rtgyhyB" }, 160189251Ssam /* SHA512 */ 161189251Ssam { "secret3", "$6$0123456789abcdef$idOsOfoWwnCQkJm9hd2hxS4NnEs9nBA9poOFXsvtrYSoSHaOToCfyUoZwKe.ZCZnq7D95tGVoi2jxZZMyVwTL1" }, 162189251Ssam { "secret4", "$6$rounds=100000$0123456789abcdef$ZiAMjbeA.iIGTWxq2oks9Bvz9sfxaoGPgAtpwimPEwFwkSNMTK7lLwABzzldds/n4UgCQ16HqawPrCrePr4YX1" }, 163189251Ssam { NULL, NULL } 164189251Ssam}; 165189251Ssam 166189251Ssamstatic void test_glibc_shapass(abts_case *tc, void *data) 167189251Ssam{ 168189251Ssam int i = 0; 169189251Ssam while (glibc_sha_pws[i].password) { 170189251Ssam apr_assert_success(tc, "check for valid glibc crypt-sha password", 171189251Ssam apr_password_validate(glibc_sha_pws[i].password, 172189251Ssam glibc_sha_pws[i].hash)); 173189251Ssam i++; 174189251Ssam } 175189251Ssam} 176189251Ssam#endif 177189251Ssam 178189251Ssamstatic void test_bcryptpass(abts_case *tc, void *data) 179189251Ssam{ 180189251Ssam const char *pass = "hellojed"; 181189251Ssam const char *pass2 = "hellojed2"; 182189251Ssam unsigned char salt[] = "sardine_sardine"; 183189251Ssam char hash[100]; 184189251Ssam const char *hash2 = "$2a$08$qipUJiI9fySUN38hcbz.lucXvAmtgowKOWYtB9y3CXyl6lTknruou"; 185189251Ssam const char *pass3 = "foobar"; 186189251Ssam 187189251Ssam apr_assert_success(tc, "bcrypt encode password", 188189251Ssam apr_bcrypt_encode(pass, 5, salt, sizeof(salt), hash, 189189251Ssam sizeof(hash))); 190189251Ssam 191189251Ssam apr_assert_success(tc, "bcrypt password validated", 192189251Ssam apr_password_validate(pass, hash)); 193189251Ssam APR_ASSERT_FAILURE(tc, "wrong bcrypt password should not validate", 194189251Ssam apr_password_validate(pass2, hash)); 195189251Ssam apr_assert_success(tc, "bcrypt password validated", 196189251Ssam apr_password_validate(pass3, hash2)); 197189251Ssam} 198189251Ssam 199189251Ssam 200189251Ssamabts_suite *testpass(abts_suite *suite) 201189251Ssam{ 202189251Ssam suite = ADD_SUITE(suite); 203189251Ssam 204189251Ssam#if CRYPT_ALGO_SUPPORTED 205189251Ssam abts_run_test(suite, test_crypt, NULL); 206189251Ssam#if APR_HAS_THREADS 207189251Ssam abts_run_test(suite, test_threadsafe, NULL); 208189251Ssam#endif 209189251Ssam#endif /* CRYPT_ALGO_SUPPORTED */ 210189251Ssam abts_run_test(suite, test_shapass, NULL); 211189251Ssam abts_run_test(suite, test_md5pass, NULL); 212189251Ssam abts_run_test(suite, test_bcryptpass, NULL); 213189251Ssam#ifdef GLIBCSHA_ALGO_SUPPORTED 214189251Ssam abts_run_test(suite, test_glibc_shapass, NULL); 215189251Ssam#endif 216189251Ssam 217189251Ssam return suite; 218189251Ssam} 219189251Ssam