2 * Copyright (C) 2009-2012 the libgit2 contributors
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.
8 # include <sys/types.h>
9 # include <sys/socket.h>
10 # include <sys/select.h>
11 # include <sys/time.h>
13 # include <arpa/inet.h>
15 # include <ws2tcpip.h>
17 # pragma comment(lib, "ws2_32")
22 # include <netinet/in.h>
26 # include <openssl/ssl.h>
27 # include <openssl/err.h>
28 # include <openssl/x509v3.h>
32 #include "git2/errors.h"
40 static void net_set_error(const char *str
)
42 int size
, error
= WSAGetLastError();
45 size
= FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
46 0, error
, 0, (LPSTR
)&err_str
, 0, 0);
50 giterr_set(GITERR_NET
, "%s: %s", str
, err_str
);
54 static void net_set_error(const char *str
)
56 giterr_set(GITERR_NET
, "%s: %s", str
, strerror(errno
));
61 static int ssl_set_error(gitno_ssl
*ssl
, int error
)
66 err
= SSL_get_error(ssl
->ssl
, error
);
68 assert(err
!= SSL_ERROR_WANT_READ
);
69 assert(err
!= SSL_ERROR_WANT_WRITE
);
72 case SSL_ERROR_WANT_CONNECT
:
73 case SSL_ERROR_WANT_ACCEPT
:
74 giterr_set(GITERR_NET
, "SSL error: connection failure\n");
76 case SSL_ERROR_WANT_X509_LOOKUP
:
77 giterr_set(GITERR_NET
, "SSL error: x509 error\n");
79 case SSL_ERROR_SYSCALL
:
82 giterr_set(GITERR_NET
, "SSL error: %s",
83 ERR_error_string(e
, NULL
));
85 } else if (error
< 0) {
86 giterr_set(GITERR_OS
, "SSL error: syscall failure");
89 giterr_set(GITERR_NET
, "SSL error: received early EOF");
93 giterr_set(GITERR_NET
, "SSL error: %s",
94 ERR_error_string(e
, NULL
));
97 case SSL_ERROR_ZERO_RETURN
:
99 giterr_set(GITERR_NET
, "SSL error: unknown error");
106 int gitno_recv(gitno_buffer
*buf
)
108 return buf
->recv(buf
);
112 static int gitno__recv_ssl(gitno_buffer
*buf
)
117 ret
= SSL_read(buf
->socket
->ssl
.ssl
, buf
->data
+ buf
->offset
, buf
->len
- buf
->offset
);
118 } while (SSL_get_error(buf
->socket
->ssl
.ssl
, ret
) == SSL_ERROR_WANT_READ
);
121 net_set_error("Error receiving socket data");
130 static int gitno__recv(gitno_buffer
*buf
)
134 ret
= p_recv(buf
->socket
->socket
, buf
->data
+ buf
->offset
, buf
->len
- buf
->offset
, 0);
136 net_set_error("Error receiving socket data");
144 void gitno_buffer_setup_callback(
145 gitno_socket
*socket
,
149 int (*recv
)(gitno_buffer
*buf
), void *cb_data
)
151 memset(data
, 0x0, len
);
155 buf
->socket
= socket
;
157 buf
->cb_data
= cb_data
;
160 void gitno_buffer_setup(gitno_socket
*socket
, gitno_buffer
*buf
, char *data
, size_t len
)
163 if (socket
->ssl
.ctx
) {
164 gitno_buffer_setup_callback(socket
, buf
, data
, len
, gitno__recv_ssl
, NULL
);
169 gitno_buffer_setup_callback(socket
, buf
, data
, len
, gitno__recv
, NULL
);
172 /* Consume up to ptr and move the rest of the buffer to the beginning */
173 void gitno_consume(gitno_buffer
*buf
, const char *ptr
)
177 assert(ptr
- buf
->data
>= 0);
178 assert(ptr
- buf
->data
<= (int) buf
->len
);
180 consumed
= ptr
- buf
->data
;
182 memmove(buf
->data
, ptr
, buf
->offset
- consumed
);
183 memset(buf
->data
+ buf
->offset
, 0x0, buf
->len
- buf
->offset
);
184 buf
->offset
-= consumed
;
187 /* Consume const bytes and move the rest of the buffer to the beginning */
188 void gitno_consume_n(gitno_buffer
*buf
, size_t cons
)
190 memmove(buf
->data
, buf
->data
+ cons
, buf
->len
- buf
->offset
);
191 memset(buf
->data
+ cons
, 0x0, buf
->len
- buf
->offset
);
197 static int gitno_ssl_teardown(gitno_ssl
*ssl
)
201 ret
= SSL_shutdown(ssl
->ssl
);
203 ret
= ssl_set_error(ssl
, ret
);
208 SSL_CTX_free(ssl
->ctx
);
212 /* Match host names according to RFC 2818 rules */
213 static int match_host(const char *pattern
, const char *host
)
216 char c
= tolower(*pattern
++);
219 return *host
? -1 : 0;
223 /* '*' at the end matches everything left */
228 * We've found a pattern, so move towards the next matching
229 * char. The '.' is handled specially because wildcards aren't
230 * allowed to cross subdomains.
234 char h
= tolower(*host
);
236 return match_host(pattern
, host
++);
238 return match_host(pattern
, host
);
244 if (c
!= tolower(*host
++))
251 static int check_host_name(const char *name
, const char *host
)
253 if (!strcasecmp(name
, host
))
256 if (match_host(name
, host
) < 0)
262 static int verify_server_cert(gitno_ssl
*ssl
, const char *host
)
265 X509_NAME
*peer_name
;
267 unsigned char *peer_cn
= NULL
;
268 int matched
= -1, type
= GEN_DNS
;
270 struct in6_addr addr6
;
271 struct in_addr addr4
;
275 if (SSL_get_verify_result(ssl
->ssl
) != X509_V_OK
) {
276 giterr_set(GITERR_SSL
, "The SSL certificate is invalid");
280 /* Try to parse the host as an IP address to see if it is */
281 if (p_inet_pton(AF_INET
, host
, &addr4
)) {
285 if(p_inet_pton(AF_INET6
, host
, &addr6
)) {
292 cert
= SSL_get_peer_certificate(ssl
->ssl
);
294 /* Check the alternative names */
295 alts
= X509_get_ext_d2i(cert
, NID_subject_alt_name
, NULL
, NULL
);
299 num
= sk_GENERAL_NAME_num(alts
);
300 for (i
= 0; i
< num
&& matched
!= 1; i
++) {
301 const GENERAL_NAME
*gn
= sk_GENERAL_NAME_value(alts
, i
);
302 const char *name
= (char *) ASN1_STRING_data(gn
->d
.ia5
);
303 size_t namelen
= (size_t) ASN1_STRING_length(gn
->d
.ia5
);
305 /* Skip any names of a type we're not looking for */
306 if (gn
->type
!= type
)
309 if (type
== GEN_DNS
) {
310 /* If it contains embedded NULs, don't even try */
311 if (memchr(name
, '\0', namelen
))
314 if (check_host_name(name
, host
) < 0)
318 } else if (type
== GEN_IPADD
) {
319 /* Here name isn't so much a name but a binary representation of the IP */
320 matched
= !!memcmp(name
, addr
, namelen
);
324 GENERAL_NAMES_free(alts
);
332 /* If no alternative names are available, check the common name */
333 peer_name
= X509_get_subject_name(cert
);
334 if (peer_name
== NULL
)
338 /* Get the index of the last CN entry */
339 while ((j
= X509_NAME_get_index_by_NID(peer_name
, NID_commonName
, i
)) >= 0)
346 str
= X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name
, i
));
350 /* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */
351 if (ASN1_STRING_type(str
) == V_ASN1_UTF8STRING
) {
352 int size
= ASN1_STRING_length(str
);
355 peer_cn
= OPENSSL_malloc(size
+ 1);
356 GITERR_CHECK_ALLOC(peer_cn
);
357 memcpy(peer_cn
, ASN1_STRING_data(str
), size
);
358 peer_cn
[size
] = '\0';
361 int size
= ASN1_STRING_to_UTF8(&peer_cn
, str
);
362 GITERR_CHECK_ALLOC(peer_cn
);
363 if (memchr(peer_cn
, '\0', size
))
367 if (check_host_name((char *)peer_cn
, host
) < 0)
370 OPENSSL_free(peer_cn
);
375 OPENSSL_free(peer_cn
);
376 return ssl_set_error(ssl
, 0);
379 OPENSSL_free(peer_cn
);
380 giterr_set(GITERR_SSL
, "Certificate host name check failed");
384 static int ssl_setup(gitno_socket
*socket
, const char *host
, int flags
)
389 SSL_load_error_strings();
390 socket
->ssl
.ctx
= SSL_CTX_new(SSLv23_method());
391 if (socket
->ssl
.ctx
== NULL
)
392 return ssl_set_error(&socket
->ssl
, 0);
394 SSL_CTX_set_mode(socket
->ssl
.ctx
, SSL_MODE_AUTO_RETRY
);
395 SSL_CTX_set_verify(socket
->ssl
.ctx
, SSL_VERIFY_NONE
, NULL
);
396 if (!SSL_CTX_set_default_verify_paths(socket
->ssl
.ctx
))
397 return ssl_set_error(&socket
->ssl
, 0);
399 socket
->ssl
.ssl
= SSL_new(socket
->ssl
.ctx
);
400 if (socket
->ssl
.ssl
== NULL
)
401 return ssl_set_error(&socket
->ssl
, 0);
403 if((ret
= SSL_set_fd(socket
->ssl
.ssl
, socket
->socket
)) == 0)
404 return ssl_set_error(&socket
->ssl
, ret
);
406 if ((ret
= SSL_connect(socket
->ssl
.ssl
)) <= 0)
407 return ssl_set_error(&socket
->ssl
, ret
);
409 if (GITNO_CONNECT_SSL_NO_CHECK_CERT
& flags
)
412 return verify_server_cert(&socket
->ssl
, host
);
416 static int gitno__close(GIT_SOCKET s
)
419 if (SOCKET_ERROR
== closesocket(s
))
422 if (0 != WSACleanup()) {
423 giterr_set(GITERR_OS
, "Winsock cleanup failed");
433 int gitno_connect(gitno_socket
*s_out
, const char *host
, const char *port
, int flags
)
435 struct addrinfo
*info
= NULL
, *p
;
436 struct addrinfo hints
;
437 GIT_SOCKET s
= INVALID_SOCKET
;
441 /* on win32, the WSA context needs to be initialized
442 * before any socket calls can be performed */
445 if (WSAStartup(MAKEWORD(2,2), &wsd
) != 0) {
446 giterr_set(GITERR_OS
, "Winsock init failed");
450 if (LOBYTE(wsd
.wVersion
) != 2 || HIBYTE(wsd
.wVersion
) != 2) {
452 giterr_set(GITERR_OS
, "Winsock init failed");
457 /* Zero the socket structure provided */
458 memset(s_out
, 0x0, sizeof(gitno_socket
));
460 memset(&hints
, 0x0, sizeof(struct addrinfo
));
461 hints
.ai_socktype
= SOCK_STREAM
;
462 hints
.ai_family
= AF_UNSPEC
;
464 if ((ret
= p_getaddrinfo(host
, port
, &hints
, &info
)) < 0) {
465 giterr_set(GITERR_NET
,
466 "Failed to resolve address for %s: %s", host
, p_gai_strerror(ret
));
470 for (p
= info
; p
!= NULL
; p
= p
->ai_next
) {
471 s
= socket(p
->ai_family
, p
->ai_socktype
, p
->ai_protocol
);
473 if (s
== INVALID_SOCKET
) {
474 net_set_error("error creating socket");
478 if (connect(s
, p
->ai_addr
, (socklen_t
)p
->ai_addrlen
) == 0)
481 /* If we can't connect, try the next one */
486 /* Oops, we couldn't connect to any address */
487 if (s
== INVALID_SOCKET
&& p
== NULL
) {
488 giterr_set(GITERR_OS
, "Failed to connect to %s", host
);
493 p_freeaddrinfo(info
);
496 if ((flags
& GITNO_CONNECT_SSL
) && ssl_setup(s_out
, host
, flags
) < 0)
499 /* SSL is not supported */
500 if (flags
& GITNO_CONNECT_SSL
) {
501 giterr_set(GITERR_OS
, "SSL is not supported by this copy of libgit2.");
510 static int gitno_send_ssl(gitno_ssl
*ssl
, const char *msg
, size_t len
, int flags
)
518 ret
= SSL_write(ssl
->ssl
, msg
+ off
, len
- off
);
519 if (ret
<= 0 && ret
!= SSL_ERROR_WANT_WRITE
)
520 return ssl_set_error(ssl
, ret
);
529 int gitno_send(gitno_socket
*socket
, const char *msg
, size_t len
, int flags
)
536 return gitno_send_ssl(&socket
->ssl
, msg
, len
, flags
);
541 ret
= p_send(socket
->socket
, msg
+ off
, len
- off
, flags
);
543 net_set_error("Error sending data");
553 int gitno_close(gitno_socket
*s
)
557 gitno_ssl_teardown(&s
->ssl
) < 0)
561 return gitno__close(s
->socket
);
564 int gitno_select_in(gitno_buffer
*buf
, long int sec
, long int usec
)
573 FD_SET(buf
->socket
->socket
, &fds
);
575 /* The select(2) interface is silly */
576 return select((int)buf
->socket
->socket
+ 1, &fds
, NULL
, NULL
, &tv
);
579 int gitno_extract_host_and_port(char **host
, char **port
, const char *url
, const char *default_port
)
581 char *colon
, *slash
, *delim
;
583 colon
= strchr(url
, ':');
584 slash
= strchr(url
, '/');
587 giterr_set(GITERR_NET
, "Malformed URL: missing /");
592 *port
= git__strdup(default_port
);
594 *port
= git__strndup(colon
+ 1, slash
- colon
- 1);
596 GITERR_CHECK_ALLOC(*port
);
598 delim
= colon
== NULL
? slash
: colon
;
599 *host
= git__strndup(url
, delim
- url
);
600 GITERR_CHECK_ALLOC(*host
);