Commit 6d0a0aca by Pierre-Olivier Latour

Fixed some Secure Transport issues on OS X

The read and write callbacks passed to SSLSetIOFuncs() have been
rewritten to match the implementation used on opensource.apple.com and
other open source projects like VLC.

This change also fixes a bug where the read callback could get into
an infinite loop when 0 bytes were read.
parent 2deb3608
...@@ -110,19 +110,26 @@ int stransport_certificate(git_cert **out, git_stream *stream) ...@@ -110,19 +110,26 @@ int stransport_certificate(git_cert **out, git_stream *stream)
return 0; return 0;
} }
/*
* Contrary to typical network IO callbacks, Secure Transport write callback is
* expected to write *all* passed data, not just as much as it can, and any
* other case would be considered a failure.
*
* This behavior is actually not specified in the Apple documentation, but is
* required for things to work correctly (and incidentally, that's also how
* Apple implements it in its projects at opensource.apple.com).
*
* Libgit2 streams happen to already have this very behavior so this is just
* passthrough.
*/
static OSStatus write_cb(SSLConnectionRef conn, const void *data, size_t *len) static OSStatus write_cb(SSLConnectionRef conn, const void *data, size_t *len)
{ {
git_stream *io = (git_stream *) conn; git_stream *io = (git_stream *) conn;
ssize_t ret;
ret = git_stream_write(io, data, *len, 0); if (git_stream_write(io, data, *len, 0) < 0) {
if (ret < 0) { return -36; /* "ioErr" from MacErrors.h which is not available on iOS */
*len = 0;
return -1;
} }
*len = ret;
return noErr; return noErr;
} }
...@@ -141,29 +148,38 @@ ssize_t stransport_write(git_stream *stream, const char *data, size_t len, int f ...@@ -141,29 +148,38 @@ ssize_t stransport_write(git_stream *stream, const char *data, size_t len, int f
return processed; return processed;
} }
/*
* Contrary to typical network IO callbacks, Secure Transport read callback is
* expected to read *exactly* the requested number of bytes, not just as much
* as it can, and any other case would be considered a failure.
*
* This behavior is actually not specified in the Apple documentation, but is
* required for things to work correctly (and incidentally, that's also how
* Apple implements it in its projects at opensource.apple.com).
*/
static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len) static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len)
{ {
git_stream *io = (git_stream *) conn; git_stream *io = (git_stream *) conn;
OSStatus error = noErr;
size_t off = 0;
ssize_t ret; ssize_t ret;
size_t left, requested;
requested = left = *len;
do { do {
ret = git_stream_read(io, data + (requested - left), left); ret = git_stream_read(io, data + off, *len - off);
if (ret < 0) { if (ret < 0) {
*len = 0; error = -36; /* "ioErr" from MacErrors.h which is not available on iOS */
return -1; break;
}
if (ret == 0) {
error = errSSLClosedGraceful;
break;
} }
left -= ret; off += ret;
} while (left); } while (off < *len);
*len = requested;
if (ret == 0)
return errSSLClosedGraceful;
return noErr; *len = off;
return error;
} }
ssize_t stransport_read(git_stream *stream, void *data, size_t len) ssize_t stransport_read(git_stream *stream, void *data, size_t len)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment