openssl_legacy.c 4.26 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * Copyright (C) the libgit2 contributors. All rights reserved.
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */

#include "streams/openssl.h"
#include "streams/openssl_legacy.h"

#include "runtime.h"
#include "git2/sys/openssl.h"

14 15 16 17 18 19 20 21 22
#if defined(GIT_OPENSSL) && !defined(GIT_OPENSSL_DYNAMIC)
# include <openssl/ssl.h>
# include <openssl/err.h>
# include <openssl/x509v3.h>
# include <openssl/bio.h>
#endif

#if defined(GIT_OPENSSL_LEGACY) || defined(GIT_OPENSSL_DYNAMIC)

23 24 25 26 27 28 29
/*
 * OpenSSL 1.1 made BIO opaque so we have to use functions to interact with it
 * which do not exist in previous versions. We define these inline functions so
 * we can program against the interface instead of littering the implementation
 * with ifdefs. We do the same for OPENSSL_init_ssl.
 */

30
int OPENSSL_init_ssl__legacy(uint64_t opts, const void *settings)
31 32 33 34
{
	GIT_UNUSED(opts);
	GIT_UNUSED(settings);
	SSL_load_error_strings();
35
	SSL_library_init();
36 37 38
	return 0;
}

39
BIO_METHOD *BIO_meth_new__legacy(int type, const char *name)
40 41 42 43 44 45 46 47 48 49 50 51
{
	BIO_METHOD *meth = git__calloc(1, sizeof(BIO_METHOD));
	if (!meth) {
		return NULL;
	}

	meth->type = type;
	meth->name = name;

	return meth;
}

52
void BIO_meth_free__legacy(BIO_METHOD *biom)
53 54 55 56
{
	git__free(biom);
}

57
int BIO_meth_set_write__legacy(BIO_METHOD *biom, int (*write) (BIO *, const char *, int))
58 59 60 61 62
{
	biom->bwrite = write;
	return 1;
}

63
int BIO_meth_set_read__legacy(BIO_METHOD *biom, int (*read) (BIO *, char *, int))
64 65 66 67 68
{
	biom->bread = read;
	return 1;
}

69
int BIO_meth_set_puts__legacy(BIO_METHOD *biom, int (*puts) (BIO *, const char *))
70 71 72 73 74
{
	biom->bputs = puts;
	return 1;
}

75
int BIO_meth_set_gets__legacy(BIO_METHOD *biom, int (*gets) (BIO *, char *, int))
76 77 78 79 80 81

{
	biom->bgets = gets;
	return 1;
}

82
int BIO_meth_set_ctrl__legacy(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *))
83 84 85 86 87
{
	biom->ctrl = ctrl;
	return 1;
}

88
int BIO_meth_set_create__legacy(BIO_METHOD *biom, int (*create) (BIO *))
89 90 91 92 93
{
	biom->create = create;
	return 1;
}

94
int BIO_meth_set_destroy__legacy(BIO_METHOD *biom, int (*destroy) (BIO *))
95 96 97 98 99
{
	biom->destroy = destroy;
	return 1;
}

100
int BIO_get_new_index__legacy(void)
101 102 103 104 105
{
	/* This exists as of 1.1 so before we'd just have 0 */
	return 0;
}

106
void BIO_set_init__legacy(BIO *b, int init)
107 108 109 110
{
	b->init = init;
}

111
void BIO_set_data__legacy(BIO *a, void *ptr)
112 113 114 115
{
	a->ptr = ptr;
}

116
void *BIO_get_data__legacy(BIO *a)
117 118 119 120
{
	return a->ptr;
}

121
const unsigned char *ASN1_STRING_get0_data__legacy(const ASN1_STRING *x)
122 123 124 125
{
	return ASN1_STRING_data((ASN1_STRING *)x);
}

126 127 128 129 130
long SSL_CTX_set_options__legacy(SSL_CTX *ctx, long op)
{
	return SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, op, NULL);
}

131 132 133
# if defined(GIT_THREADS)
static git_mutex *openssl_locks;

134
static void openssl_locking_function(int mode, int n, const char *file, int line)
135 136 137 138 139 140 141 142
{
	int lock;

	GIT_UNUSED(file);
	GIT_UNUSED(line);

	lock = mode & CRYPTO_LOCK;

143
	if (lock)
144
		(void)git_mutex_lock(&openssl_locks[n]);
145
	else
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
		git_mutex_unlock(&openssl_locks[n]);
}

static void shutdown_ssl_locking(void)
{
	int num_locks, i;

	num_locks = CRYPTO_num_locks();
	CRYPTO_set_locking_callback(NULL);

	for (i = 0; i < num_locks; ++i)
		git_mutex_free(&openssl_locks[i]);
	git__free(openssl_locks);
}

static void threadid_cb(CRYPTO_THREADID *threadid)
{
	GIT_UNUSED(threadid);
	CRYPTO_THREADID_set_numeric(threadid, git_thread_currentid());
}

int git_openssl_set_locking(void)
{
	int num_locks, i;

171 172 173 174 175 176 177 178 179 180 181 182 183 184
#ifndef GIT_THREADS
	git_error_set(GIT_ERROR_THREAD, "libgit2 was not built with threads");
	return -1;
#endif

#ifdef GIT_OPENSSL_DYNAMIC
	/*
	 * This function is required on legacy versions of OpenSSL; when building
	 * with dynamically-loaded OpenSSL, we detect whether we loaded it or not.
	 */
	if (!CRYPTO_set_locking_callback)
		return 0;
#endif

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
	CRYPTO_THREADID_set_callback(threadid_cb);

	num_locks = CRYPTO_num_locks();
	openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
	GIT_ERROR_CHECK_ALLOC(openssl_locks);

	for (i = 0; i < num_locks; i++) {
		if (git_mutex_init(&openssl_locks[i]) != 0) {
			git_error_set(GIT_ERROR_SSL, "failed to initialize openssl locks");
			return -1;
		}
	}

	CRYPTO_set_locking_callback(openssl_locking_function);
	return git_runtime_shutdown_register(shutdown_ssl_locking);
}
#endif /* GIT_THREADS */

203
#endif /* GIT_OPENSSL_LEGACY || GIT_OPENSSL_DYNAMIC */