Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
3 - *
4 - * This file is part of libgit2, distributed under the GNU GPL v2 with
5 - * a Linking Exception. For full terms see the included COPYING file.
6 - */
7 -
8 - #include "streams/openssl.h"
9 -
10 - #ifdef GIT_OPENSSL
11 -
12 - #include <ctype.h>
13 -
14 - #include "global.h"
15 - #include "posix.h"
16 - #include "stream.h"
17 - #include "streams/socket.h"
18 - #include "netops.h"
19 - #include "git2/transport.h"
20 - #include "git2/sys/openssl.h"
21 -
22 - #ifndef GIT_WIN32
23 - # include <sys/types.h>
24 - # include <sys/socket.h>
25 - # include <netinet/in.h>
26 - #endif
27 -
28 - #include <openssl/ssl.h>
29 - #include <openssl/err.h>
30 - #include <openssl/x509v3.h>
31 - #include <openssl/bio.h>
32 -
33 - SSL_CTX *git__ssl_ctx;
34 -
35 - #define GIT_SSL_DEFAULT_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA"
36 -
37 - #if (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L) || \
38 - (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
39 - # define OPENSSL_LEGACY_API
40 - #endif
41 -
42 - /*
43 - * OpenSSL 1.1 made BIO opaque so we have to use functions to interact with it
44 - * which do not exist in previous versions. We define these inline functions so
45 - * we can program against the interface instead of littering the implementation
46 - * with ifdefs. We do the same for OPENSSL_init_ssl.
47 - */
48 - #if defined(OPENSSL_LEGACY_API)
49 9 2 static int OPENSSL_init_ssl(int opts, void *settings)
50 - {
51 - GIT_UNUSED(opts);
52 - GIT_UNUSED(settings);
53 9 2 SSL_load_error_strings();
54 9 3 OpenSSL_add_ssl_algorithms();
55 9 4 return 0;
56 - }
57 -
58 9 2 static BIO_METHOD* BIO_meth_new(int type, const char *name)
59 - {
60 9 2 BIO_METHOD *meth = git__calloc(1, sizeof(BIO_METHOD));
61 9 3 if (!meth) {
62 ##### 4 return NULL;
63 - }
64 -
65 9 5 meth->type = type;
66 9 5 meth->name = name;
67 -
68 9 5 return meth;
69 - }
70 -
71 9 2 static void BIO_meth_free(BIO_METHOD *biom)
72 - {
73 9 2 git__free(biom);
74 9 3 }
75 -
76 9 2 static int BIO_meth_set_write(BIO_METHOD *biom, int (*write) (BIO *, const char *, int))
77 - {
78 9 2 biom->bwrite = write;
79 9 2 return 1;
80 - }
81 -
82 9 2 static int BIO_meth_set_read(BIO_METHOD *biom, int (*read) (BIO *, char *, int))
83 - {
84 9 2 biom->bread = read;
85 9 2 return 1;
86 - }
87 -
88 9 2 static int BIO_meth_set_puts(BIO_METHOD *biom, int (*puts) (BIO *, const char *))
89 - {
90 9 2 biom->bputs = puts;
91 9 2 return 1;
92 - }
93 -
94 9 2 static int BIO_meth_set_gets(BIO_METHOD *biom, int (*gets) (BIO *, char *, int))
95 -
96 - {
97 9 2 biom->bgets = gets;
98 9 2 return 1;
99 - }
100 -
101 9 2 static int BIO_meth_set_ctrl(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *))
102 - {
103 9 2 biom->ctrl = ctrl;
104 9 2 return 1;
105 - }
106 -
107 9 2 static int BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *))
108 - {
109 9 2 biom->create = create;
110 9 2 return 1;
111 - }
112 -
113 9 2 static int BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *))
114 - {
115 9 2 biom->destroy = destroy;
116 9 2 return 1;
117 - }
118 -
119 9 2 static int BIO_get_new_index(void)
120 - {
121 - /* This exists as of 1.1 so before we'd just have 0 */
122 9 2 return 0;
123 - }
124 -
125 48 2 static void BIO_set_init(BIO *b, int init)
126 - {
127 48 2 b->init = init;
128 48 2 }
129 -
130 144 2 static void BIO_set_data(BIO *a, void *ptr)
131 - {
132 144 2 a->ptr = ptr;
133 144 2 }
134 -
135 2275 2 static void *BIO_get_data(BIO *a)
136 - {
137 2275 2 return a->ptr;
138 - }
139 -
140 52 2 static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x)
141 - {
142 52 2 return ASN1_STRING_data((ASN1_STRING *)x);
143 - }
144 -
145 - # if defined(GIT_THREADS)
146 - static git_mutex *openssl_locks;
147 -
148 ##### 2 static void openssl_locking_function(
149 - int mode, int n, const char *file, int line)
150 - {
151 - int lock;
152 -
153 - GIT_UNUSED(file);
154 - GIT_UNUSED(line);
155 -
156 ##### 2 lock = mode & CRYPTO_LOCK;
157 -
158 ##### 2 if (lock) {
159 ##### 3 (void)git_mutex_lock(&openssl_locks[n]);
160 - } else {
161 ##### 4 git_mutex_unlock(&openssl_locks[n]);
162 - }
163 ##### 5 }
164 -
165 ##### 2 static void shutdown_ssl_locking(void)
166 - {
167 - int num_locks, i;
168 -
169 ##### 2 num_locks = CRYPTO_num_locks();
170 ##### 3 CRYPTO_set_locking_callback(NULL);
171 -
172 ##### 4,6,7 for (i = 0; i < num_locks; ++i)
173 ##### 5 git_mutex_free(&openssl_locks[i]);
174 ##### 8 git__free(openssl_locks);
175 ##### 9 }
176 - # endif /* GIT_THREADS */
177 - #endif /* OPENSSL_LEGACY_API */
178 -
179 - static BIO_METHOD *git_stream_bio_method;
180 - static int init_bio_method(void);
181 -
182 - /**
183 - * This function aims to clean-up the SSL context which
184 - * we allocated.
185 - */
186 9 2 static void shutdown_ssl(void)
187 - {
188 9 2 if (git_stream_bio_method) {
189 9 3 BIO_meth_free(git_stream_bio_method);
190 9 4 git_stream_bio_method = NULL;
191 - }
192 -
193 9 5 if (git__ssl_ctx) {
194 9 6 SSL_CTX_free(git__ssl_ctx);
195 9 7 git__ssl_ctx = NULL;
196 - }
197 9 8 }
198 -
199 - #ifdef VALGRIND
200 - #ifdef OPENSSL_LEGACY_API
201 - static void *git_openssl_malloc(size_t bytes)
202 - {
203 - return git__calloc(1, bytes);
204 - }
205 -
206 - static void *git_openssl_realloc(void *mem, size_t size)
207 - {
208 - return git__realloc(mem, size);
209 - }
210 -
211 - static void git_openssl_free(void *mem)
212 - {
213 - return git__free(mem);
214 - }
215 - #else
216 - static void *git_openssl_malloc(size_t bytes, const char *file, int line)
217 - {
218 - GIT_UNUSED(file);
219 - GIT_UNUSED(line);
220 - return git__calloc(1, bytes);
221 - }
222 -
223 - static void *git_openssl_realloc(void *mem, size_t size, const char *file, int line)
224 - {
225 - GIT_UNUSED(file);
226 - GIT_UNUSED(line);
227 - return git__realloc(mem, size);
228 - }
229 -
230 - static void git_openssl_free(void *mem, const char *file, int line)
231 - {
232 - GIT_UNUSED(file);
233 - GIT_UNUSED(line);
234 - return git__free(mem);
235 - }
236 - #endif
237 - #endif
238 -
239 9 2 int git_openssl_stream_global_init(void)
240 - {
241 9 2 long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
242 9 2 const char *ciphers = git_libgit2__ssl_ciphers();
243 - #ifdef VALGRIND
244 - static bool allocators_initialized = false;
245 - #endif
246 -
247 - /* Older OpenSSL and MacOS OpenSSL doesn't have this */
248 - #ifdef SSL_OP_NO_COMPRESSION
249 9 3 ssl_opts |= SSL_OP_NO_COMPRESSION;
250 - #endif
251 -
252 - #ifdef VALGRIND
253 - /* Swap in our own allocator functions that initialize allocated memory */
254 - if (!allocators_initialized &&
255 - CRYPTO_set_mem_functions(git_openssl_malloc,
256 - git_openssl_realloc,
257 - git_openssl_free) != 1)
258 - goto error;
259 - allocators_initialized = true;
260 - #endif
261 -
262 9 3 OPENSSL_init_ssl(0, NULL);
263 -
264 - /*
265 - * Load SSLv{2,3} and TLSv1 so that we can talk with servers
266 - * which use the SSL hellos, which are often used for
267 - * compatibility. We then disable SSL so we only allow OpenSSL
268 - * to speak TLSv1 to perform the encryption itself.
269 - */
270 9 4-6 if (!(git__ssl_ctx = SSL_CTX_new(SSLv23_method())))
271 ##### 7 goto error;
272 -
273 9 8 SSL_CTX_set_options(git__ssl_ctx, ssl_opts);
274 9 9 SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY);
275 9 10 SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL);
276 9 11,12 if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx))
277 ##### 13 goto error;
278 -
279 9 14 if (!ciphers)
280 9 15 ciphers = GIT_SSL_DEFAULT_CIPHERS;
281 -
282 9 16,17 if(!SSL_CTX_set_cipher_list(git__ssl_ctx, ciphers))
283 ##### 18 goto error;
284 -
285 9 19,20 if (init_bio_method() < 0)
286 ##### 21 goto error;
287 -
288 9 22 git__on_shutdown(shutdown_ssl);
289 -
290 9 23 return 0;
291 -
292 - error:
293 ##### 24-26 git_error_set(GIT_ERROR_NET, "could not initialize openssl: %s",
294 - ERR_error_string(ERR_get_error(), NULL));
295 ##### 27 SSL_CTX_free(git__ssl_ctx);
296 ##### 28 git__ssl_ctx = NULL;
297 ##### 28 return -1;
298 - }
299 -
300 - #if defined(GIT_THREADS) && defined(OPENSSL_LEGACY_API)
301 ##### 2 static void threadid_cb(CRYPTO_THREADID *threadid)
302 - {
303 - GIT_UNUSED(threadid);
304 ##### 2,3 CRYPTO_THREADID_set_numeric(threadid, git_thread_currentid());
305 ##### 4 }
306 - #endif
307 -
308 ##### 2 int git_openssl_set_locking(void)
309 - {
310 - #if defined(GIT_THREADS) && defined(OPENSSL_LEGACY_API)
311 - int num_locks, i;
312 -
313 ##### 2 CRYPTO_THREADID_set_callback(threadid_cb);
314 -
315 ##### 3 num_locks = CRYPTO_num_locks();
316 ##### 4 openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
317 ##### 5,6 GIT_ERROR_CHECK_ALLOC(openssl_locks);
318 -
319 ##### 7,12,13 for (i = 0; i < num_locks; i++) {
320 ##### 8,9 if (git_mutex_init(&openssl_locks[i]) != 0) {
321 ##### 10 git_error_set(GIT_ERROR_SSL, "failed to initialize openssl locks");
322 ##### 11 return -1;
323 - }
324 - }
325 -
326 ##### 14 CRYPTO_set_locking_callback(openssl_locking_function);
327 ##### 15 git__on_shutdown(shutdown_ssl_locking);
328 ##### 16 return 0;
329 - #elif !defined(OPENSSL_LEGACY_API)
330 - return 0;
331 - #else
332 - git_error_set(GIT_ERROR_THREAD, "libgit2 was not built with threads");
333 - return -1;
334 - #endif
335 - }
336 -
337 -
338 48 2 static int bio_create(BIO *b)
339 - {
340 48 2 BIO_set_init(b, 1);
341 48 3 BIO_set_data(b, NULL);
342 -
343 48 4 return 1;
344 - }
345 -
346 48 2 static int bio_destroy(BIO *b)
347 - {
348 48 2 if (!b)
349 ##### 3 return 0;
350 -
351 48 4 BIO_set_data(b, NULL);
352 -
353 48 5 return 1;
354 - }
355 -
356 2039 2 static int bio_read(BIO *b, char *buf, int len)
357 - {
358 2039 2 git_stream *io = (git_stream *) BIO_get_data(b);
359 -
360 2039 3 return (int) git_stream_read(io, buf, len);
361 - }
362 -
363 236 2 static int bio_write(BIO *b, const char *buf, int len)
364 - {
365 236 2 git_stream *io = (git_stream *) BIO_get_data(b);
366 236 3 return (int) git_stream_write(io, buf, len, 0);
367 - }
368 -
369 144 2 static long bio_ctrl(BIO *b, int cmd, long num, void *ptr)
370 - {
371 - GIT_UNUSED(b);
372 - GIT_UNUSED(num);
373 - GIT_UNUSED(ptr);
374 -
375 144 2 if (cmd == BIO_CTRL_FLUSH)
376 48 3 return 1;
377 -
378 96 4 return 0;
379 - }
380 -
381 ##### 2 static int bio_gets(BIO *b, char *buf, int len)
382 - {
383 - GIT_UNUSED(b);
384 - GIT_UNUSED(buf);
385 - GIT_UNUSED(len);
386 ##### 2 return -1;
387 - }
388 -
389 ##### 2 static int bio_puts(BIO *b, const char *str)
390 - {
391 ##### 2 return bio_write(b, str, strlen(str));
392 - }
393 -
394 9 2 static int init_bio_method(void)
395 - {
396 - /* Set up the BIO_METHOD we use for wrapping our own stream implementations */
397 9 2,3 git_stream_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK | BIO_get_new_index(), "git_stream");
398 9 4,5 GIT_ERROR_CHECK_ALLOC(git_stream_bio_method);
399 -
400 9 6 BIO_meth_set_write(git_stream_bio_method, bio_write);
401 9 7 BIO_meth_set_read(git_stream_bio_method, bio_read);
402 9 8 BIO_meth_set_puts(git_stream_bio_method, bio_puts);
403 9 9 BIO_meth_set_gets(git_stream_bio_method, bio_gets);
404 9 10 BIO_meth_set_ctrl(git_stream_bio_method, bio_ctrl);
405 9 11 BIO_meth_set_create(git_stream_bio_method, bio_create);
406 9 12 BIO_meth_set_destroy(git_stream_bio_method, bio_destroy);
407 -
408 9 13 return 0;
409 - }
410 -
411 ##### 2 static int ssl_set_error(SSL *ssl, int error)
412 - {
413 - int err;
414 - unsigned long e;
415 -
416 ##### 2 err = SSL_get_error(ssl, error);
417 -
418 ##### 3,4 assert(err != SSL_ERROR_WANT_READ);
419 ##### 5,6 assert(err != SSL_ERROR_WANT_WRITE);
420 -
421 ##### 7 switch (err) {
422 - case SSL_ERROR_WANT_CONNECT:
423 - case SSL_ERROR_WANT_ACCEPT:
424 ##### 8 git_error_set(GIT_ERROR_SSL, "SSL error: connection failure");
425 ##### 9 break;
426 - case SSL_ERROR_WANT_X509_LOOKUP:
427 ##### 10 git_error_set(GIT_ERROR_SSL, "SSL error: x509 error");
428 ##### 11 break;
429 - case SSL_ERROR_SYSCALL:
430 ##### 12 e = ERR_get_error();
431 ##### 13 if (e > 0) {
432 - char errmsg[256];
433 ##### 14 ERR_error_string_n(e, errmsg, sizeof(errmsg));
434 ##### 15 git_error_set(GIT_ERROR_NET, "SSL error: %s", errmsg);
435 ##### 16,17 break;
436 ##### 18 } else if (error < 0) {
437 ##### 19 git_error_set(GIT_ERROR_OS, "SSL error: syscall failure");
438 ##### 20 break;
439 - }
440 ##### 21 git_error_set(GIT_ERROR_SSL, "SSL error: received early EOF");
441 ##### 22 return GIT_EEOF;
442 - break;
443 - case SSL_ERROR_SSL:
444 - {
445 - char errmsg[256];
446 ##### 23 e = ERR_get_error();
447 ##### 24 ERR_error_string_n(e, errmsg, sizeof(errmsg));
448 ##### 25 git_error_set(GIT_ERROR_SSL, "SSL error: %s", errmsg);
449 ##### 26,27 break;
450 - }
451 - case SSL_ERROR_NONE:
452 - case SSL_ERROR_ZERO_RETURN:
453 - default:
454 ##### 28 git_error_set(GIT_ERROR_SSL, "SSL error: unknown error");
455 ##### 29 break;
456 - }
457 ##### 30 return -1;
458 - }
459 -
460 48 2 static int ssl_teardown(SSL *ssl)
461 - {
462 - int ret;
463 -
464 48 2 ret = SSL_shutdown(ssl);
465 48 3 if (ret < 0)
466 ##### 4 ret = ssl_set_error(ssl, ret);
467 - else
468 48 5 ret = 0;
469 -
470 48 6 return ret;
471 - }
472 -
473 52 2 static int check_host_name(const char *name, const char *host)
474 - {
475 52 2 if (!strcasecmp(name, host))
476 41 3 return 0;
477 -
478 11 4,5 if (gitno__match_host(name, host) < 0)
479 10 6 return -1;
480 -
481 1 7 return 0;
482 - }
483 -
484 48 2 static int verify_server_cert(SSL *ssl, const char *host)
485 - {
486 48 2 X509 *cert = NULL;
487 - X509_NAME *peer_name;
488 - ASN1_STRING *str;
489 48 2 unsigned char *peer_cn = NULL;
490 48 2 int matched = -1, type = GEN_DNS;
491 - GENERAL_NAMES *alts;
492 - struct in6_addr addr6;
493 - struct in_addr addr4;
494 48 2 void *addr = NULL;
495 48 2 int i = -1, j, error = 0;
496 -
497 48 2,3 if (SSL_get_verify_result(ssl) != X509_V_OK) {
498 4 4 git_error_set(GIT_ERROR_SSL, "the SSL certificate is invalid");
499 4 5 return GIT_ECERTIFICATE;
500 - }
501 -
502 - /* Try to parse the host as an IP address to see if it is */
503 44 6,7 if (p_inet_pton(AF_INET, host, &addr4)) {
504 ##### 8 type = GEN_IPADD;
505 ##### 8 addr = &addr4;
506 - } else {
507 44 9,10 if (p_inet_pton(AF_INET6, host, &addr6)) {
508 ##### 11 type = GEN_IPADD;
509 ##### 11 addr = &addr6;
510 - }
511 - }
512 -
513 -
514 44 12 cert = SSL_get_peer_certificate(ssl);
515 44 13 if (!cert) {
516 ##### 14 error = -1;
517 ##### 14 git_error_set(GIT_ERROR_SSL, "the server did not provide a certificate");
518 ##### 15 goto cleanup;
519 - }
520 -
521 - /* Check the alternative names */
522 44 16 alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
523 44 17 if (alts) {
524 - int num;
525 -
526 44 18 num = sk_GENERAL_NAME_num(alts);
527 96 19,39-41 for (i = 0; i < num && matched != 1; i++) {
528 52 20 const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i);
529 52 21 const char *name = (char *) ASN1_STRING_get0_data(gn->d.ia5);
530 52 22 size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5);
531 -
532 - /* Skip any names of a type we're not looking for */
533 52 23 if (gn->type != type)
534 ##### 24 continue;
535 -
536 52 25 if (type == GEN_DNS) {
537 - /* If it contains embedded NULs, don't even try */
538 52 26 if (memchr(name, '\0', namelen))
539 ##### 27 continue;
540 -
541 52 28,29 if (check_host_name(name, host) < 0)
542 10 30 matched = 0;
543 - else
544 52 31,32 matched = 1;
545 ##### 33 } else if (type == GEN_IPADD) {
546 - /* Here name isn't so much a name but a binary representation of the IP */
547 ##### 34-38 matched = addr && !!memcmp(name, addr, namelen);
548 - }
549 - }
550 - }
551 44 42 GENERAL_NAMES_free(alts);
552 -
553 44 43 if (matched == 0)
554 2 44 goto cert_fail_name;
555 -
556 42 45 if (matched == 1) {
557 42 46 goto cleanup;
558 - }
559 -
560 - /* If no alternative names are available, check the common name */
561 ##### 47 peer_name = X509_get_subject_name(cert);
562 ##### 48 if (peer_name == NULL)
563 ##### 49 goto on_error;
564 -
565 ##### 50 if (peer_name) {
566 - /* Get the index of the last CN entry */
567 ##### 51,53,54 while ((j = X509_NAME_get_index_by_NID(peer_name, NID_commonName, i)) >= 0)
568 ##### 52 i = j;
569 - }
570 -
571 ##### 55 if (i < 0)
572 ##### 56 goto on_error;
573 -
574 ##### 57,58 str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name, i));
575 ##### 59 if (str == NULL)
576 ##### 60 goto on_error;
577 -
578 - /* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */
579 ##### 61,62 if (ASN1_STRING_type(str) == V_ASN1_UTF8STRING) {
580 ##### 63 int size = ASN1_STRING_length(str);
581 -
582 ##### 64 if (size > 0) {
583 ##### 65 peer_cn = OPENSSL_malloc(size + 1);
584 ##### 66,67 GIT_ERROR_CHECK_ALLOC(peer_cn);
585 ##### 68 memcpy(peer_cn, ASN1_STRING_get0_data(str), size);
586 ##### 69 peer_cn[size] = '\0';
587 - } else {
588 ##### 70,71 goto cert_fail_name;
589 - }
590 - } else {
591 ##### 72 int size = ASN1_STRING_to_UTF8(&peer_cn, str);
592 ##### 73,74 GIT_ERROR_CHECK_ALLOC(peer_cn);
593 ##### 75 if (memchr(peer_cn, '\0', size))
594 ##### 76 goto cert_fail_name;
595 - }
596 -
597 ##### 77,78 if (check_host_name((char *)peer_cn, host) < 0)
598 ##### 79 goto cert_fail_name;
599 -
600 ##### 80 goto cleanup;
601 -
602 - cert_fail_name:
603 2 81 error = GIT_ECERTIFICATE;
604 2 81 git_error_set(GIT_ERROR_SSL, "hostname does not match certificate");
605 2 82 goto cleanup;
606 -
607 - on_error:
608 ##### 83 error = ssl_set_error(ssl, 0);
609 ##### 84 goto cleanup;
610 -
611 - cleanup:
612 44 85 X509_free(cert);
613 44 86 OPENSSL_free(peer_cn);
614 44 87 return error;
615 - }
616 -
617 - typedef struct {
618 - git_stream parent;
619 - git_stream *io;
620 - int owned;
621 - bool connected;
622 - char *host;
623 - SSL *ssl;
624 - git_cert_x509 cert_info;
625 - } openssl_stream;
626 -
627 48 2 static int openssl_connect(git_stream *stream)
628 - {
629 - int ret;
630 - BIO *bio;
631 48 2 openssl_stream *st = (openssl_stream *) stream;
632 -
633 48 2-4 if (st->owned && (ret = git_stream_connect(st->io)) < 0)
634 ##### 5 return ret;
635 -
636 48 6 bio = BIO_new(git_stream_bio_method);
637 48 7,8 GIT_ERROR_CHECK_ALLOC(bio);
638 -
639 48 9 BIO_set_data(bio, st->io);
640 48 10 SSL_set_bio(st->ssl, bio, bio);
641 -
642 - /* specify the host in case SNI is needed */
643 - #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
644 48 11 SSL_set_tlsext_host_name(st->ssl, st->host);
645 - #endif
646 -
647 48 12,13 if ((ret = SSL_connect(st->ssl)) <= 0)
648 ##### 14 return ssl_set_error(st->ssl, ret);
649 -
650 48 15 st->connected = true;
651 -
652 48 15 return verify_server_cert(st->ssl, st->host);
653 - }
654 -
655 33 2 static int openssl_certificate(git_cert **out, git_stream *stream)
656 - {
657 33 2 openssl_stream *st = (openssl_stream *) stream;
658 33 2 X509 *cert = SSL_get_peer_certificate(st->ssl);
659 33 3 unsigned char *guard, *encoded_cert = NULL;
660 - int error, len;
661 -
662 - /* Retrieve the length of the certificate first */
663 33 3 len = i2d_X509(cert, NULL);
664 33 4 if (len < 0) {
665 ##### 5 git_error_set(GIT_ERROR_NET, "failed to retrieve certificate information");
666 ##### 6 error = -1;
667 ##### 6 goto out;
668 - }
669 -
670 33 7 encoded_cert = git__malloc(len);
671 33 8,9 GIT_ERROR_CHECK_ALLOC(encoded_cert);
672 - /* i2d_X509 makes 'guard' point to just after the data */
673 33 10 guard = encoded_cert;
674 -
675 33 10 len = i2d_X509(cert, &guard);
676 33 11 if (len < 0) {
677 ##### 12 git_error_set(GIT_ERROR_NET, "failed to retrieve certificate information");
678 ##### 13 error = -1;
679 ##### 13 goto out;
680 - }
681 -
682 33 14 st->cert_info.parent.cert_type = GIT_CERT_X509;
683 33 14 st->cert_info.data = encoded_cert;
684 33 14 st->cert_info.len = len;
685 33 14 encoded_cert = NULL;
686 -
687 33 14 *out = &st->cert_info.parent;
688 33 14 error = 0;
689 -
690 - out:
691 33 15 git__free(encoded_cert);
692 33 16 X509_free(cert);
693 33 17 return error;
694 - }
695 -
696 ##### 2 static int openssl_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts)
697 - {
698 ##### 2 openssl_stream *st = (openssl_stream *) stream;
699 -
700 ##### 2 return git_stream_set_proxy(st->io, proxy_opts);
701 - }
702 -
703 92 2 static ssize_t openssl_write(git_stream *stream, const char *data, size_t data_len, int flags)
704 - {
705 92 2 openssl_stream *st = (openssl_stream *) stream;
706 92 2 int ret, len = min(data_len, INT_MAX);
707 -
708 - GIT_UNUSED(flags);
709 -
710 92 2,3 if ((ret = SSL_write(st->ssl, data, len)) <= 0)
711 ##### 4,5 return ssl_set_error(st->ssl, ret);
712 -
713 92 6 return ret;
714 - }
715 -
716 673 2 static ssize_t openssl_read(git_stream *stream, void *data, size_t len)
717 - {
718 673 2 openssl_stream *st = (openssl_stream *) stream;
719 - int ret;
720 -
721 673 2,3 if ((ret = SSL_read(st->ssl, data, len)) <= 0)
722 ##### 4,5 return ssl_set_error(st->ssl, ret);
723 -
724 673 6 return ret;
725 - }
726 -
727 48 2 static int openssl_close(git_stream *stream)
728 - {
729 48 2 openssl_stream *st = (openssl_stream *) stream;
730 - int ret;
731 -
732 48 2-4 if (st->connected && (ret = ssl_teardown(st->ssl)) < 0)
733 ##### 5 return -1;
734 -
735 48 6 st->connected = false;
736 -
737 48 6 return st->owned ? git_stream_close(st->io) : 0;
738 - }
739 -
740 49 2 static void openssl_free(git_stream *stream)
741 - {
742 49 2 openssl_stream *st = (openssl_stream *) stream;
743 -
744 49 2 if (st->owned)
745 49 3 git_stream_free(st->io);
746 -
747 49 4 SSL_free(st->ssl);
748 49 5 git__free(st->host);
749 49 6 git__free(st->cert_info.data);
750 49 7 git__free(st);
751 49 8 }
752 -
753 49 2 static int openssl_stream_wrap(
754 - git_stream **out,
755 - git_stream *in,
756 - const char *host,
757 - int owned)
758 - {
759 - openssl_stream *st;
760 -
761 49 2-5 assert(out && in && host);
762 -
763 49 6 st = git__calloc(1, sizeof(openssl_stream));
764 49 7,8 GIT_ERROR_CHECK_ALLOC(st);
765 -
766 49 9 st->io = in;
767 49 9 st->owned = owned;
768 -
769 49 9 st->ssl = SSL_new(git__ssl_ctx);
770 49 10 if (st->ssl == NULL) {
771 ##### 11 git_error_set(GIT_ERROR_SSL, "failed to create ssl object");
772 ##### 12 git__free(st);
773 ##### 13 return -1;
774 - }
775 -
776 49 14 st->host = git__strdup(host);
777 49 15,16 GIT_ERROR_CHECK_ALLOC(st->host);
778 -
779 49 17 st->parent.version = GIT_STREAM_VERSION;
780 49 17 st->parent.encrypted = 1;
781 49 17 st->parent.proxy_support = git_stream_supports_proxy(st->io);
782 49 18 st->parent.connect = openssl_connect;
783 49 18 st->parent.certificate = openssl_certificate;
784 49 18 st->parent.set_proxy = openssl_set_proxy;
785 49 18 st->parent.read = openssl_read;
786 49 18 st->parent.write = openssl_write;
787 49 18 st->parent.close = openssl_close;
788 49 18 st->parent.free = openssl_free;
789 -
790 49 18 *out = (git_stream *) st;
791 49 18 return 0;
792 - }
793 -
794 ##### 2 int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host)
795 - {
796 ##### 2 return openssl_stream_wrap(out, in, host, 0);
797 - }
798 -
799 49 2 int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
800 - {
801 49 2 git_stream *stream = NULL;
802 - int error;
803 -
804 49 2-5 assert(out && host && port);
805 -
806 49 6,7 if ((error = git_socket_stream_new(&stream, host, port)) < 0)
807 ##### 8 return error;
808 -
809 49 9,10 if ((error = openssl_stream_wrap(out, stream, host, 1)) < 0) {
810 ##### 11 git_stream_close(stream);
811 ##### 12 git_stream_free(stream);
812 - }
813 -
814 49 13 return error;
815 - }
816 -
817 ##### 2 int git_openssl__set_cert_location(const char *file, const char *path)
818 - {
819 ##### 2,3 if (SSL_CTX_load_verify_locations(git__ssl_ctx, file, path) == 0) {
820 - char errmsg[256];
821 -
822 ##### 4,5 ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
823 ##### 6 git_error_set(GIT_ERROR_SSL, "OpenSSL error: failed to load certificates: %s",
824 - errmsg);
825 -
826 ##### 7 return -1;
827 - }
828 ##### 8 return 0;
829 - }
830 -
831 - #else
832 -
833 - #include "stream.h"
834 - #include "git2/sys/openssl.h"
835 -
836 - int git_openssl_stream_global_init(void)
837 - {
838 - return 0;
839 - }
840 -
841 - int git_openssl_set_locking(void)
842 - {
843 - git_error_set(GIT_ERROR_SSL, "libgit2 was not built with OpenSSL support");
844 - return -1;
845 - }
846 -
847 - #endif