rugged 1.6.5 → 1.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged_allocator.c +0 -54
  3. data/lib/rugged/version.rb +1 -1
  4. data/vendor/libgit2/CMakeLists.txt +3 -8
  5. data/vendor/libgit2/cmake/CheckPrototypeDefinitionSafe.cmake +16 -0
  6. data/vendor/libgit2/cmake/SelectGSSAPI.cmake +3 -3
  7. data/vendor/libgit2/cmake/SelectHTTPSBackend.cmake +21 -2
  8. data/vendor/libgit2/cmake/SelectHashes.cmake +4 -0
  9. data/vendor/libgit2/cmake/SelectXdiff.cmake +9 -0
  10. data/vendor/libgit2/deps/pcre/LICENCE +5 -5
  11. data/vendor/libgit2/deps/pcre/pcre.h +2 -2
  12. data/vendor/libgit2/deps/pcre/pcre_compile.c +6 -3
  13. data/vendor/libgit2/deps/pcre/pcre_exec.c +2 -2
  14. data/vendor/libgit2/deps/xdiff/CMakeLists.txt +28 -0
  15. data/vendor/libgit2/{src/libgit2 → deps}/xdiff/git-xdiff.h +4 -1
  16. data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xdiffi.c +19 -18
  17. data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xdiffi.h +2 -4
  18. data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xemit.c +3 -3
  19. data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xhistogram.c +7 -18
  20. data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xmacros.h +18 -1
  21. data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xmerge.c +24 -22
  22. data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xpatience.c +21 -30
  23. data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xprepare.c +13 -30
  24. data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xutils.c +18 -1
  25. data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xutils.h +2 -1
  26. data/vendor/libgit2/include/git2/common.h +26 -1
  27. data/vendor/libgit2/include/git2/diff.h +41 -3
  28. data/vendor/libgit2/include/git2/errors.h +4 -2
  29. data/vendor/libgit2/include/git2/index.h +9 -0
  30. data/vendor/libgit2/include/git2/oid.h +1 -1
  31. data/vendor/libgit2/include/git2/remote.h +18 -0
  32. data/vendor/libgit2/include/git2/repository.h +12 -2
  33. data/vendor/libgit2/include/git2/sys/alloc.h +0 -34
  34. data/vendor/libgit2/include/git2/sys/commit_graph.h +12 -2
  35. data/vendor/libgit2/include/git2/sys/midx.h +5 -1
  36. data/vendor/libgit2/include/git2/sys/stream.h +16 -2
  37. data/vendor/libgit2/include/git2/sys/transport.h +20 -2
  38. data/vendor/libgit2/include/git2/version.h +4 -4
  39. data/vendor/libgit2/include/git2/worktree.h +3 -1
  40. data/vendor/libgit2/src/CMakeLists.txt +34 -11
  41. data/vendor/libgit2/src/cli/cmd_clone.c +22 -6
  42. data/vendor/libgit2/src/cli/progress.c +9 -8
  43. data/vendor/libgit2/src/cli/progress.h +4 -4
  44. data/vendor/libgit2/src/libgit2/CMakeLists.txt +1 -19
  45. data/vendor/libgit2/src/libgit2/annotated_commit.c +2 -2
  46. data/vendor/libgit2/src/libgit2/annotated_commit.h +1 -1
  47. data/vendor/libgit2/src/libgit2/apply.c +4 -3
  48. data/vendor/libgit2/src/libgit2/blame.c +23 -16
  49. data/vendor/libgit2/src/libgit2/blame_git.c +0 -1
  50. data/vendor/libgit2/src/libgit2/branch.c +2 -2
  51. data/vendor/libgit2/src/libgit2/cherrypick.c +3 -3
  52. data/vendor/libgit2/src/libgit2/clone.c +3 -1
  53. data/vendor/libgit2/src/libgit2/commit.c +31 -9
  54. data/vendor/libgit2/src/libgit2/commit_graph.c +110 -43
  55. data/vendor/libgit2/src/libgit2/commit_graph.h +20 -4
  56. data/vendor/libgit2/src/libgit2/commit_list.c +12 -5
  57. data/vendor/libgit2/src/libgit2/commit_list.h +1 -0
  58. data/vendor/libgit2/src/libgit2/config_file.c +14 -8
  59. data/vendor/libgit2/src/libgit2/describe.c +10 -7
  60. data/vendor/libgit2/src/libgit2/diff.c +16 -7
  61. data/vendor/libgit2/src/libgit2/diff.h +6 -6
  62. data/vendor/libgit2/src/libgit2/diff_file.c +7 -7
  63. data/vendor/libgit2/src/libgit2/diff_generate.c +36 -15
  64. data/vendor/libgit2/src/libgit2/diff_parse.c +20 -4
  65. data/vendor/libgit2/src/libgit2/diff_print.c +26 -7
  66. data/vendor/libgit2/src/libgit2/diff_tform.c +4 -4
  67. data/vendor/libgit2/src/libgit2/diff_xdiff.h +1 -1
  68. data/vendor/libgit2/src/libgit2/email.c +4 -3
  69. data/vendor/libgit2/src/libgit2/errors.c +73 -18
  70. data/vendor/libgit2/src/libgit2/fetch.c +37 -9
  71. data/vendor/libgit2/src/libgit2/fetch.h +0 -2
  72. data/vendor/libgit2/src/libgit2/fetchhead.c +11 -9
  73. data/vendor/libgit2/src/libgit2/grafts.c +272 -0
  74. data/vendor/libgit2/src/libgit2/grafts.h +36 -0
  75. data/vendor/libgit2/src/libgit2/ident.c +3 -3
  76. data/vendor/libgit2/src/libgit2/index.c +323 -120
  77. data/vendor/libgit2/src/libgit2/index.h +14 -1
  78. data/vendor/libgit2/src/libgit2/indexer.c +10 -3
  79. data/vendor/libgit2/src/libgit2/iterator.c +20 -5
  80. data/vendor/libgit2/src/libgit2/iterator.h +3 -0
  81. data/vendor/libgit2/src/libgit2/libgit2.c +39 -0
  82. data/vendor/libgit2/src/libgit2/merge.c +14 -9
  83. data/vendor/libgit2/src/libgit2/merge_file.c +0 -2
  84. data/vendor/libgit2/src/libgit2/midx.c +66 -37
  85. data/vendor/libgit2/src/libgit2/midx.h +13 -3
  86. data/vendor/libgit2/src/libgit2/notes.c +9 -8
  87. data/vendor/libgit2/src/libgit2/object.c +40 -15
  88. data/vendor/libgit2/src/libgit2/object.h +6 -0
  89. data/vendor/libgit2/src/libgit2/odb.c +11 -5
  90. data/vendor/libgit2/src/libgit2/odb_pack.c +16 -3
  91. data/vendor/libgit2/src/libgit2/oid.c +7 -1
  92. data/vendor/libgit2/src/libgit2/oidarray.c +49 -3
  93. data/vendor/libgit2/src/libgit2/oidarray.h +5 -1
  94. data/vendor/libgit2/src/libgit2/pack-objects.c +19 -12
  95. data/vendor/libgit2/src/libgit2/pack-objects.h +5 -2
  96. data/vendor/libgit2/src/libgit2/pack.c +3 -3
  97. data/vendor/libgit2/src/libgit2/parse.c +7 -4
  98. data/vendor/libgit2/src/libgit2/parse.h +1 -1
  99. data/vendor/libgit2/src/libgit2/patch.h +7 -1
  100. data/vendor/libgit2/src/libgit2/patch_generate.c +24 -5
  101. data/vendor/libgit2/src/libgit2/patch_parse.c +16 -8
  102. data/vendor/libgit2/src/libgit2/push.c +2 -2
  103. data/vendor/libgit2/src/libgit2/reader.c +1 -1
  104. data/vendor/libgit2/src/libgit2/rebase.c +72 -84
  105. data/vendor/libgit2/src/libgit2/refdb_fs.c +22 -13
  106. data/vendor/libgit2/src/libgit2/refs.c +8 -1
  107. data/vendor/libgit2/src/libgit2/remote.c +15 -6
  108. data/vendor/libgit2/src/libgit2/remote.h +1 -0
  109. data/vendor/libgit2/src/libgit2/repository.c +580 -301
  110. data/vendor/libgit2/src/libgit2/repository.h +17 -2
  111. data/vendor/libgit2/src/libgit2/reset.c +2 -2
  112. data/vendor/libgit2/src/libgit2/revert.c +8 -11
  113. data/vendor/libgit2/src/libgit2/revwalk.c +26 -4
  114. data/vendor/libgit2/src/libgit2/stash.c +9 -8
  115. data/vendor/libgit2/src/libgit2/streams/mbedtls.c +0 -1
  116. data/vendor/libgit2/src/libgit2/streams/openssl.c +8 -16
  117. data/vendor/libgit2/src/libgit2/streams/schannel.c +715 -0
  118. data/vendor/libgit2/src/libgit2/streams/schannel.h +28 -0
  119. data/vendor/libgit2/src/libgit2/streams/socket.c +237 -51
  120. data/vendor/libgit2/src/libgit2/streams/socket.h +3 -1
  121. data/vendor/libgit2/src/libgit2/streams/stransport.c +40 -12
  122. data/vendor/libgit2/src/libgit2/streams/tls.c +5 -0
  123. data/vendor/libgit2/src/libgit2/submodule.h +3 -3
  124. data/vendor/libgit2/src/libgit2/threadstate.c +15 -2
  125. data/vendor/libgit2/src/libgit2/threadstate.h +1 -3
  126. data/vendor/libgit2/src/libgit2/transports/auth.h +1 -2
  127. data/vendor/libgit2/src/libgit2/transports/{auth_negotiate.c → auth_gssapi.c} +32 -32
  128. data/vendor/libgit2/src/libgit2/transports/auth_negotiate.h +1 -1
  129. data/vendor/libgit2/src/libgit2/transports/auth_ntlm.h +1 -1
  130. data/vendor/libgit2/src/libgit2/transports/{auth_ntlm.c → auth_ntlmclient.c} +12 -12
  131. data/vendor/libgit2/src/libgit2/transports/auth_sspi.c +341 -0
  132. data/vendor/libgit2/src/libgit2/transports/git.c +7 -8
  133. data/vendor/libgit2/src/libgit2/transports/http.c +7 -2
  134. data/vendor/libgit2/src/libgit2/transports/httpclient.c +5 -0
  135. data/vendor/libgit2/src/libgit2/transports/local.c +13 -4
  136. data/vendor/libgit2/src/libgit2/transports/smart.c +33 -27
  137. data/vendor/libgit2/src/libgit2/transports/smart.h +23 -8
  138. data/vendor/libgit2/src/libgit2/transports/smart_pkt.c +135 -15
  139. data/vendor/libgit2/src/libgit2/transports/smart_protocol.c +154 -47
  140. data/vendor/libgit2/src/libgit2/transports/ssh.c +3 -3
  141. data/vendor/libgit2/src/libgit2/transports/winhttp.c +14 -15
  142. data/vendor/libgit2/src/libgit2/tree-cache.c +26 -16
  143. data/vendor/libgit2/src/libgit2/tree-cache.h +5 -3
  144. data/vendor/libgit2/src/libgit2/tree.c +1 -1
  145. data/vendor/libgit2/src/libgit2/worktree.c +25 -10
  146. data/vendor/libgit2/src/util/alloc.c +65 -6
  147. data/vendor/libgit2/src/util/alloc.h +34 -9
  148. data/vendor/libgit2/src/util/allocators/failalloc.c +0 -60
  149. data/vendor/libgit2/src/util/allocators/failalloc.h +0 -6
  150. data/vendor/libgit2/src/util/allocators/stdalloc.c +2 -105
  151. data/vendor/libgit2/src/util/allocators/win32_leakcheck.c +0 -68
  152. data/vendor/libgit2/src/util/array.h +6 -1
  153. data/vendor/libgit2/src/util/cc-compat.h +2 -0
  154. data/vendor/libgit2/src/util/filebuf.c +6 -1
  155. data/vendor/libgit2/src/util/filebuf.h +19 -6
  156. data/vendor/libgit2/src/util/fs_path.c +1 -1
  157. data/vendor/libgit2/src/util/futils.c +8 -5
  158. data/vendor/libgit2/src/util/git2_features.h.in +9 -3
  159. data/vendor/libgit2/src/util/net.c +308 -157
  160. data/vendor/libgit2/src/util/net.h +25 -0
  161. data/vendor/libgit2/src/util/posix.c +54 -0
  162. data/vendor/libgit2/src/util/posix.h +22 -0
  163. data/vendor/libgit2/src/util/rand.c +6 -4
  164. data/vendor/libgit2/src/util/staticstr.h +66 -0
  165. data/vendor/libgit2/src/util/util.c +15 -10
  166. data/vendor/libgit2/src/util/util.h +24 -16
  167. data/vendor/libgit2/src/util/win32/error.c +1 -1
  168. data/vendor/libgit2/src/util/win32/path_w32.c +8 -8
  169. data/vendor/libgit2/src/util/win32/posix_w32.c +1 -1
  170. data/vendor/libgit2/src/util/win32/utf-conv.c +73 -75
  171. data/vendor/libgit2/src/util/win32/utf-conv.h +81 -14
  172. data/vendor/libgit2/src/util/win32/w32_util.c +1 -1
  173. metadata +28 -22
  174. data/vendor/libgit2/cmake/SelectWinHTTP.cmake +0 -17
  175. data/vendor/libgit2/src/libgit2/netops.c +0 -124
  176. data/vendor/libgit2/src/libgit2/netops.h +0 -68
  177. /data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xdiff.h +0 -0
  178. /data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xemit.h +0 -0
  179. /data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xinclude.h +0 -0
  180. /data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xprepare.h +0 -0
  181. /data/vendor/libgit2/{src/libgit2 → deps}/xdiff/xtypes.h +0 -0
@@ -0,0 +1,715 @@
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/schannel.h"
9
+
10
+ #ifdef GIT_SCHANNEL
11
+
12
+ #define SECURITY_WIN32
13
+
14
+ #include <security.h>
15
+ #include <schannel.h>
16
+ #include <sspi.h>
17
+
18
+ #include "stream.h"
19
+ #include "streams/socket.h"
20
+
21
+ #ifndef SP_PROT_TLS1_2_CLIENT
22
+ # define SP_PROT_TLS1_2_CLIENT 2048
23
+ #endif
24
+
25
+ #ifndef SP_PROT_TLS1_3_CLIENT
26
+ # define SP_PROT_TLS1_3_CLIENT 8192
27
+ #endif
28
+
29
+ #ifndef SECBUFFER_ALERT
30
+ # define SECBUFFER_ALERT 17
31
+ #endif
32
+
33
+ #define READ_BLOCKSIZE (16 * 1024)
34
+
35
+ typedef enum {
36
+ STATE_NONE = 0,
37
+ STATE_CRED = 1,
38
+ STATE_CONTEXT = 2,
39
+ STATE_CERTIFICATE = 3
40
+ } schannel_state;
41
+
42
+ typedef struct {
43
+ git_stream parent;
44
+ git_stream *io;
45
+ int owned;
46
+ bool connected;
47
+ wchar_t *host_w;
48
+
49
+ schannel_state state;
50
+
51
+ CredHandle cred;
52
+ CtxtHandle context;
53
+ SecPkgContext_StreamSizes stream_sizes;
54
+
55
+ CERT_CONTEXT *certificate;
56
+ const CERT_CHAIN_CONTEXT *cert_chain;
57
+ git_cert_x509 x509;
58
+
59
+ git_str plaintext_in;
60
+ git_str ciphertext_in;
61
+ } schannel_stream;
62
+
63
+ static int connect_context(schannel_stream *st)
64
+ {
65
+ SCHANNEL_CRED cred = { 0 };
66
+ SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
67
+ DWORD context_flags;
68
+ static size_t MAX_RETRIES = 1024;
69
+ size_t retries;
70
+ ssize_t read_len;
71
+ int error = 0;
72
+
73
+ if (st->owned && (error = git_stream_connect(st->io)) < 0)
74
+ return error;
75
+
76
+ cred.dwVersion = SCHANNEL_CRED_VERSION;
77
+ cred.dwFlags = SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
78
+ SCH_CRED_IGNORE_REVOCATION_OFFLINE |
79
+ SCH_CRED_MANUAL_CRED_VALIDATION |
80
+ SCH_CRED_NO_DEFAULT_CREDS |
81
+ SCH_CRED_NO_SERVERNAME_CHECK;
82
+ cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT |
83
+ SP_PROT_TLS1_3_CLIENT;
84
+
85
+ if (AcquireCredentialsHandleW(NULL, SCHANNEL_NAME_W,
86
+ SECPKG_CRED_OUTBOUND, NULL, &cred, NULL,
87
+ NULL, &st->cred, NULL) != SEC_E_OK) {
88
+ git_error_set(GIT_ERROR_OS, "could not acquire credentials handle");
89
+ return -1;
90
+ }
91
+
92
+ st->state = STATE_CRED;
93
+
94
+ context_flags = ISC_REQ_ALLOCATE_MEMORY |
95
+ ISC_REQ_CONFIDENTIALITY |
96
+ ISC_REQ_REPLAY_DETECT |
97
+ ISC_REQ_SEQUENCE_DETECT |
98
+ ISC_REQ_STREAM;
99
+
100
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
101
+ SecBuffer input_buf[] = {
102
+ { (unsigned long)st->ciphertext_in.size,
103
+ SECBUFFER_TOKEN,
104
+ st->ciphertext_in.size ? st->ciphertext_in.ptr : NULL },
105
+ { 0, SECBUFFER_EMPTY, NULL }
106
+ };
107
+ SecBuffer output_buf[] = { { 0, SECBUFFER_TOKEN, NULL },
108
+ { 0, SECBUFFER_ALERT, NULL } };
109
+
110
+ SecBufferDesc input_buf_desc = { SECBUFFER_VERSION, 2, input_buf };
111
+ SecBufferDesc output_buf_desc = { SECBUFFER_VERSION, 2, output_buf };
112
+
113
+ status = InitializeSecurityContextW(&st->cred,
114
+ retries ? &st->context : NULL, st->host_w,
115
+ context_flags, 0, 0, retries ? &input_buf_desc : NULL, 0,
116
+ retries ? NULL : &st->context, &output_buf_desc,
117
+ &context_flags, NULL);
118
+
119
+ if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED) {
120
+ st->state = STATE_CONTEXT;
121
+
122
+ if (output_buf[0].cbBuffer > 0) {
123
+ error = git_stream__write_full(st->io,
124
+ output_buf[0].pvBuffer,
125
+ output_buf[0].cbBuffer, 0);
126
+
127
+ FreeContextBuffer(output_buf[0].pvBuffer);
128
+ }
129
+
130
+ /* handle any leftover, unprocessed data */
131
+ if (input_buf[1].BufferType == SECBUFFER_EXTRA) {
132
+ GIT_ASSERT(st->ciphertext_in.size > input_buf[1].cbBuffer);
133
+
134
+ git_str_consume_bytes(&st->ciphertext_in,
135
+ st->ciphertext_in.size - input_buf[1].cbBuffer);
136
+ } else {
137
+ git_str_clear(&st->ciphertext_in);
138
+ }
139
+
140
+ if (error < 0 || status == SEC_E_OK)
141
+ break;
142
+ } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
143
+ /* we need additional data from the client; */
144
+ if (git_str_grow_by(&st->ciphertext_in, READ_BLOCKSIZE) < 0) {
145
+ error = -1;
146
+ break;
147
+ }
148
+
149
+ if ((read_len = git_stream_read(st->io,
150
+ st->ciphertext_in.ptr + st->ciphertext_in.size,
151
+ (st->ciphertext_in.asize - st->ciphertext_in.size))) < 0) {
152
+ error = -1;
153
+ break;
154
+ }
155
+
156
+ GIT_ASSERT((size_t)read_len <=
157
+ st->ciphertext_in.asize - st->ciphertext_in.size);
158
+ st->ciphertext_in.size += read_len;
159
+ } else {
160
+ git_error_set(GIT_ERROR_OS,
161
+ "could not initialize security context");
162
+ error = -1;
163
+ break;
164
+ }
165
+
166
+ GIT_ASSERT(st->ciphertext_in.size < ULONG_MAX);
167
+ }
168
+
169
+ if (retries == MAX_RETRIES) {
170
+ git_error_set(GIT_ERROR_SSL,
171
+ "could not initialize security context: too many retries");
172
+ error = -1;
173
+ }
174
+
175
+ if (!error) {
176
+ if (QueryContextAttributesW(&st->context,
177
+ SECPKG_ATTR_STREAM_SIZES,
178
+ &st->stream_sizes) != SEC_E_OK) {
179
+ git_error_set(GIT_ERROR_SSL,
180
+ "could not query stream sizes");
181
+ error = -1;
182
+ }
183
+ }
184
+
185
+ return error;
186
+ }
187
+
188
+ static int set_certificate_lookup_error(DWORD status)
189
+ {
190
+ switch (status) {
191
+ case CERT_TRUST_IS_NOT_TIME_VALID:
192
+ git_error_set(GIT_ERROR_SSL,
193
+ "certificate is expired or not yet valid");
194
+ break;
195
+ case CERT_TRUST_IS_REVOKED:
196
+ git_error_set(GIT_ERROR_SSL, "certificate is revoked");
197
+ break;
198
+ case CERT_TRUST_IS_NOT_SIGNATURE_VALID:
199
+ case CERT_TRUST_IS_NOT_VALID_FOR_USAGE:
200
+ case CERT_TRUST_INVALID_EXTENSION:
201
+ case CERT_TRUST_INVALID_POLICY_CONSTRAINTS:
202
+ case CERT_TRUST_INVALID_BASIC_CONSTRAINTS:
203
+ case CERT_TRUST_INVALID_NAME_CONSTRAINTS:
204
+ case CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT:
205
+ case CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT:
206
+ case CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT:
207
+ case CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT:
208
+ case CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY:
209
+ case CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT:
210
+ git_error_set(GIT_ERROR_SSL, "certificate is not valid");
211
+ break;
212
+ case CERT_TRUST_IS_UNTRUSTED_ROOT:
213
+ case CERT_TRUST_IS_CYCLIC:
214
+ case CERT_TRUST_IS_EXPLICIT_DISTRUST:
215
+ git_error_set(GIT_ERROR_SSL, "certificate is not trusted");
216
+ break;
217
+ case CERT_TRUST_REVOCATION_STATUS_UNKNOWN:
218
+ git_error_set(GIT_ERROR_SSL,
219
+ "certificate revocation status could not be verified");
220
+ break;
221
+ case CERT_TRUST_IS_OFFLINE_REVOCATION:
222
+ git_error_set(GIT_ERROR_SSL,
223
+ "certificate revocation is offline or stale");
224
+ break;
225
+ case CERT_TRUST_HAS_WEAK_SIGNATURE:
226
+ git_error_set(GIT_ERROR_SSL, "certificate has a weak signature");
227
+ break;
228
+ default:
229
+ git_error_set(GIT_ERROR_SSL,
230
+ "unknown certificate lookup failure: %d", status);
231
+ return -1;
232
+ }
233
+
234
+ return GIT_ECERTIFICATE;
235
+ }
236
+
237
+ static int set_certificate_validation_error(DWORD status)
238
+ {
239
+ switch (status) {
240
+ case TRUST_E_CERT_SIGNATURE:
241
+ git_error_set(GIT_ERROR_SSL,
242
+ "the certificate cannot be verified");
243
+ break;
244
+ case CRYPT_E_REVOKED:
245
+ git_error_set(GIT_ERROR_SSL,
246
+ "the certificate or signature has been revoked");
247
+ break;
248
+ case CERT_E_UNTRUSTEDROOT:
249
+ git_error_set(GIT_ERROR_SSL,
250
+ "the certificate root is not trusted");
251
+ break;
252
+ case CERT_E_UNTRUSTEDTESTROOT:
253
+ git_error_set(GIT_ERROR_SSL,
254
+ "the certificate root is a test certificate");
255
+ break;
256
+ case CERT_E_CHAINING:
257
+ git_error_set(GIT_ERROR_SSL,
258
+ "the certificate chain is invalid");
259
+ break;
260
+ case CERT_E_WRONG_USAGE:
261
+ case CERT_E_PURPOSE:
262
+ git_error_set(GIT_ERROR_SSL,
263
+ "the certificate is not valid for this usage");
264
+ break;
265
+ case CERT_E_EXPIRED:
266
+ git_error_set(GIT_ERROR_SSL,
267
+ "certificate is expired or not yet valid");
268
+ break;
269
+ case CERT_E_INVALID_NAME:
270
+ case CERT_E_CN_NO_MATCH:
271
+ git_error_set(GIT_ERROR_SSL,
272
+ "certificate is not valid for this hostname");
273
+ break;
274
+ case CERT_E_INVALID_POLICY:
275
+ case TRUST_E_BASIC_CONSTRAINTS:
276
+ case CERT_E_CRITICAL:
277
+ case CERT_E_VALIDITYPERIODNESTING:
278
+ git_error_set(GIT_ERROR_SSL, "certificate is not valid");
279
+ break;
280
+ case CRYPT_E_NO_REVOCATION_CHECK:
281
+ git_error_set(GIT_ERROR_SSL,
282
+ "certificate revocation status could not be verified");
283
+ break;
284
+ case CRYPT_E_REVOCATION_OFFLINE:
285
+ git_error_set(GIT_ERROR_SSL,
286
+ "certificate revocation is offline or stale");
287
+ break;
288
+ case CERT_E_ROLE:
289
+ git_error_set(GIT_ERROR_SSL, "certificate authority is not valid");
290
+ break;
291
+ default:
292
+ git_error_set(GIT_ERROR_SSL,
293
+ "unknown certificate policy checking failure: %d",
294
+ status);
295
+ return -1;
296
+ }
297
+
298
+ return GIT_ECERTIFICATE;
299
+ }
300
+
301
+ static int check_certificate(schannel_stream* st)
302
+ {
303
+ CERT_CHAIN_PARA cert_chain_parameters;
304
+ SSL_EXTRA_CERT_CHAIN_POLICY_PARA ssl_policy_parameters;
305
+ CERT_CHAIN_POLICY_PARA cert_policy_parameters =
306
+ { sizeof(CERT_CHAIN_POLICY_PARA), 0, &ssl_policy_parameters };
307
+ CERT_CHAIN_POLICY_STATUS cert_policy_status;
308
+
309
+ memset(&cert_chain_parameters, 0, sizeof(CERT_CHAIN_PARA));
310
+ cert_chain_parameters.cbSize = sizeof(CERT_CHAIN_PARA);
311
+
312
+ if (QueryContextAttributesW(&st->context,
313
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT,
314
+ &st->certificate) != SEC_E_OK) {
315
+ git_error_set(GIT_ERROR_OS,
316
+ "could not query remote certificate context");
317
+ return -1;
318
+ }
319
+
320
+ /* TODO: do we really want to do revokcation checking ? */
321
+ if (!CertGetCertificateChain(NULL, st->certificate, NULL,
322
+ st->certificate->hCertStore, &cert_chain_parameters,
323
+ CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
324
+ NULL, &st->cert_chain)) {
325
+ git_error_set(GIT_ERROR_OS, "could not query remote certificate chain");
326
+ CertFreeCertificateContext(st->certificate);
327
+ return -1;
328
+ }
329
+
330
+ st->state = STATE_CERTIFICATE;
331
+
332
+ /* Set up the x509 certificate data for future callbacks */
333
+
334
+ st->x509.parent.cert_type = GIT_CERT_X509;
335
+ st->x509.data = st->certificate->pbCertEncoded;
336
+ st->x509.len = st->certificate->cbCertEncoded;
337
+
338
+ /* Handle initial certificate validation */
339
+
340
+ if (st->cert_chain->TrustStatus.dwErrorStatus != CERT_TRUST_NO_ERROR)
341
+ return set_certificate_lookup_error(st->cert_chain->TrustStatus.dwErrorStatus);
342
+
343
+ ssl_policy_parameters.cbSize = sizeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA);
344
+ ssl_policy_parameters.dwAuthType = AUTHTYPE_SERVER;
345
+ ssl_policy_parameters.pwszServerName = st->host_w;
346
+
347
+ if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
348
+ st->cert_chain, &cert_policy_parameters,
349
+ &cert_policy_status)) {
350
+ git_error_set(GIT_ERROR_OS, "could not verify certificate chain policy");
351
+ return -1;
352
+ }
353
+
354
+ if (cert_policy_status.dwError != SEC_E_OK)
355
+ return set_certificate_validation_error(cert_policy_status.dwError);
356
+
357
+ return 0;
358
+ }
359
+
360
+ static int schannel_connect(git_stream *stream)
361
+ {
362
+ schannel_stream *st = (schannel_stream *)stream;
363
+ int error;
364
+
365
+ GIT_ASSERT(st->state == STATE_NONE);
366
+
367
+ if ((error = connect_context(st)) < 0 ||
368
+ (error = check_certificate(st)) < 0)
369
+ return error;
370
+
371
+ st->connected = 1;
372
+ return 0;
373
+ }
374
+
375
+ static int schannel_certificate(git_cert **out, git_stream *stream)
376
+ {
377
+ schannel_stream *st = (schannel_stream *)stream;
378
+
379
+ *out = &st->x509.parent;
380
+ return 0;
381
+ }
382
+
383
+ static int schannel_set_proxy(
384
+ git_stream *stream,
385
+ const git_proxy_options *proxy_options)
386
+ {
387
+ schannel_stream *st = (schannel_stream *)stream;
388
+ return git_stream_set_proxy(st->io, proxy_options);
389
+ }
390
+
391
+ static ssize_t schannel_write(
392
+ git_stream *stream,
393
+ const char *data,
394
+ size_t data_len,
395
+ int flags)
396
+ {
397
+ schannel_stream *st = (schannel_stream *)stream;
398
+ SecBuffer encrypt_buf[3];
399
+ SecBufferDesc encrypt_buf_desc = { SECBUFFER_VERSION, 3, encrypt_buf };
400
+ git_str ciphertext_out = GIT_STR_INIT;
401
+ ssize_t total_len = 0;
402
+
403
+ GIT_UNUSED(flags);
404
+
405
+ if (data_len > SSIZE_MAX)
406
+ data_len = SSIZE_MAX;
407
+
408
+ git_str_init(&ciphertext_out,
409
+ st->stream_sizes.cbHeader +
410
+ st->stream_sizes.cbMaximumMessage +
411
+ st->stream_sizes.cbTrailer);
412
+
413
+ while (data_len > 0) {
414
+ size_t message_len = min(data_len, st->stream_sizes.cbMaximumMessage);
415
+ size_t ciphertext_len, ciphertext_written = 0;
416
+
417
+ encrypt_buf[0].BufferType = SECBUFFER_STREAM_HEADER;
418
+ encrypt_buf[0].cbBuffer = st->stream_sizes.cbHeader;
419
+ encrypt_buf[0].pvBuffer = ciphertext_out.ptr;
420
+
421
+ encrypt_buf[1].BufferType = SECBUFFER_DATA;
422
+ encrypt_buf[1].cbBuffer = (unsigned long)message_len;
423
+ encrypt_buf[1].pvBuffer =
424
+ ciphertext_out.ptr + st->stream_sizes.cbHeader;
425
+
426
+ encrypt_buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
427
+ encrypt_buf[2].cbBuffer = st->stream_sizes.cbTrailer;
428
+ encrypt_buf[2].pvBuffer =
429
+ ciphertext_out.ptr + st->stream_sizes.cbHeader +
430
+ message_len;
431
+
432
+ memcpy(ciphertext_out.ptr + st->stream_sizes.cbHeader, data, message_len);
433
+
434
+ if (EncryptMessage(&st->context, 0, &encrypt_buf_desc, 0) != SEC_E_OK) {
435
+ git_error_set(GIT_ERROR_OS, "could not encrypt tls message");
436
+ total_len = -1;
437
+ goto done;
438
+ }
439
+
440
+ ciphertext_len = encrypt_buf[0].cbBuffer +
441
+ encrypt_buf[1].cbBuffer +
442
+ encrypt_buf[2].cbBuffer;
443
+
444
+ while (ciphertext_written < ciphertext_len) {
445
+ ssize_t chunk_len = git_stream_write(st->io,
446
+ ciphertext_out.ptr + ciphertext_written,
447
+ ciphertext_len - ciphertext_written, 0);
448
+
449
+ if (chunk_len < 0) {
450
+ total_len = -1;
451
+ goto done;
452
+ }
453
+
454
+ ciphertext_len -= chunk_len;
455
+ ciphertext_written += chunk_len;
456
+ }
457
+
458
+ total_len += message_len;
459
+
460
+ data += message_len;
461
+ data_len -= message_len;
462
+ }
463
+
464
+ done:
465
+ git_str_dispose(&ciphertext_out);
466
+ return total_len;
467
+ }
468
+
469
+ static ssize_t schannel_read(git_stream *stream, void *_data, size_t data_len)
470
+ {
471
+ schannel_stream *st = (schannel_stream *)stream;
472
+ char *data = (char *)_data;
473
+ SecBuffer decrypt_buf[4];
474
+ SecBufferDesc decrypt_buf_desc = { SECBUFFER_VERSION, 4, decrypt_buf };
475
+ SECURITY_STATUS status;
476
+ ssize_t chunk_len, total_len = 0;
477
+
478
+ if (data_len > SSIZE_MAX)
479
+ data_len = SSIZE_MAX;
480
+
481
+ /*
482
+ * Loop until we have some bytes to return - we may have decrypted
483
+ * bytes queued or ciphertext from the wire that we can decrypt and
484
+ * return. Return any queued bytes if they're available to avoid a
485
+ * network read, which may block. We may return less than the
486
+ * caller requested, and they can retry for an actual network
487
+ */
488
+ while ((size_t)total_len < data_len) {
489
+ if (st->plaintext_in.size > 0) {
490
+ size_t copy_len = min(st->plaintext_in.size, data_len);
491
+
492
+ memcpy(data, st->plaintext_in.ptr, copy_len);
493
+ git_str_consume_bytes(&st->plaintext_in, copy_len);
494
+
495
+ data += copy_len;
496
+ data_len -= copy_len;
497
+
498
+ total_len += copy_len;
499
+
500
+ continue;
501
+ }
502
+
503
+ if (st->ciphertext_in.size > 0) {
504
+ decrypt_buf[0].BufferType = SECBUFFER_DATA;
505
+ decrypt_buf[0].cbBuffer = (unsigned long)min(st->ciphertext_in.size, ULONG_MAX);
506
+ decrypt_buf[0].pvBuffer = st->ciphertext_in.ptr;
507
+
508
+ decrypt_buf[1].BufferType = SECBUFFER_EMPTY;
509
+ decrypt_buf[1].cbBuffer = 0;
510
+ decrypt_buf[1].pvBuffer = NULL;
511
+
512
+ decrypt_buf[2].BufferType = SECBUFFER_EMPTY;
513
+ decrypt_buf[2].cbBuffer = 0;
514
+ decrypt_buf[2].pvBuffer = NULL;
515
+
516
+ decrypt_buf[3].BufferType = SECBUFFER_EMPTY;
517
+ decrypt_buf[3].cbBuffer = 0;
518
+ decrypt_buf[3].pvBuffer = NULL;
519
+
520
+ status = DecryptMessage(&st->context, &decrypt_buf_desc, 0, NULL);
521
+
522
+ if (status == SEC_E_OK) {
523
+ GIT_ASSERT(decrypt_buf[0].BufferType == SECBUFFER_STREAM_HEADER);
524
+ GIT_ASSERT(decrypt_buf[1].BufferType == SECBUFFER_DATA);
525
+ GIT_ASSERT(decrypt_buf[2].BufferType == SECBUFFER_STREAM_TRAILER);
526
+
527
+ if (git_str_put(&st->plaintext_in, decrypt_buf[1].pvBuffer, decrypt_buf[1].cbBuffer) < 0) {
528
+ total_len = -1;
529
+ goto done;
530
+ }
531
+
532
+ if (decrypt_buf[3].BufferType == SECBUFFER_EXTRA) {
533
+ git_str_consume_bytes(&st->ciphertext_in, (st->ciphertext_in.size - decrypt_buf[3].cbBuffer));
534
+ } else {
535
+ git_str_clear(&st->ciphertext_in);
536
+ }
537
+
538
+ continue;
539
+ } else if (status == SEC_E_CONTEXT_EXPIRED) {
540
+ break;
541
+ } else if (status != SEC_E_INCOMPLETE_MESSAGE) {
542
+ git_error_set(GIT_ERROR_SSL, "could not decrypt tls message");
543
+ total_len = -1;
544
+ goto done;
545
+ }
546
+ }
547
+
548
+ if (total_len != 0)
549
+ break;
550
+
551
+ if (git_str_grow_by(&st->ciphertext_in, READ_BLOCKSIZE) < 0) {
552
+ total_len = -1;
553
+ goto done;
554
+ }
555
+
556
+ if ((chunk_len = git_stream_read(st->io, st->ciphertext_in.ptr + st->ciphertext_in.size, st->ciphertext_in.asize - st->ciphertext_in.size)) < 0) {
557
+ total_len = -1;
558
+ goto done;
559
+ }
560
+
561
+ st->ciphertext_in.size += chunk_len;
562
+ }
563
+
564
+ done:
565
+ return total_len;
566
+ }
567
+
568
+ static int schannel_close(git_stream *stream)
569
+ {
570
+ schannel_stream *st = (schannel_stream *)stream;
571
+ int error = 0;
572
+
573
+ if (st->connected) {
574
+ SecBuffer shutdown_buf;
575
+ SecBufferDesc shutdown_buf_desc =
576
+ { SECBUFFER_VERSION, 1, &shutdown_buf };
577
+ DWORD shutdown_message = SCHANNEL_SHUTDOWN, shutdown_flags;
578
+
579
+ shutdown_buf.BufferType = SECBUFFER_TOKEN;
580
+ shutdown_buf.cbBuffer = sizeof(DWORD);
581
+ shutdown_buf.pvBuffer = &shutdown_message;
582
+
583
+ if (ApplyControlToken(&st->context, &shutdown_buf_desc) != SEC_E_OK) {
584
+ git_error_set(GIT_ERROR_SSL, "could not shutdown stream");
585
+ error = -1;
586
+ }
587
+
588
+ shutdown_buf.BufferType = SECBUFFER_TOKEN;
589
+ shutdown_buf.cbBuffer = 0;
590
+ shutdown_buf.pvBuffer = NULL;
591
+
592
+ shutdown_flags = ISC_REQ_ALLOCATE_MEMORY |
593
+ ISC_REQ_CONFIDENTIALITY |
594
+ ISC_REQ_REPLAY_DETECT |
595
+ ISC_REQ_SEQUENCE_DETECT |
596
+ ISC_REQ_STREAM;
597
+
598
+ if (InitializeSecurityContext(&st->cred, &st->context,
599
+ NULL, shutdown_flags, 0, 0,
600
+ &shutdown_buf_desc, 0, NULL,
601
+ &shutdown_buf_desc, &shutdown_flags,
602
+ NULL) == SEC_E_OK) {
603
+ if (shutdown_buf.cbBuffer > 0) {
604
+ if (git_stream__write_full(st->io,
605
+ shutdown_buf.pvBuffer,
606
+ shutdown_buf.cbBuffer, 0) < 0)
607
+ error = -1;
608
+
609
+ FreeContextBuffer(shutdown_buf.pvBuffer);
610
+ }
611
+ }
612
+ }
613
+
614
+ st->connected = false;
615
+
616
+ if (st->owned && git_stream_close(st->io) < 0)
617
+ error = -1;
618
+
619
+ return error;
620
+ }
621
+
622
+ static void schannel_free(git_stream *stream)
623
+ {
624
+ schannel_stream *st = (schannel_stream *)stream;
625
+
626
+ if (st->state >= STATE_CERTIFICATE) {
627
+ CertFreeCertificateContext(st->certificate);
628
+ CertFreeCertificateChain(st->cert_chain);
629
+ }
630
+
631
+ if (st->state >= STATE_CONTEXT)
632
+ DeleteSecurityContext(&st->context);
633
+
634
+ if (st->state >= STATE_CRED)
635
+ FreeCredentialsHandle(&st->cred);
636
+
637
+ st->state = STATE_NONE;
638
+
639
+ git_str_dispose(&st->ciphertext_in);
640
+ git_str_dispose(&st->plaintext_in);
641
+
642
+ git__free(st->host_w);
643
+
644
+ if (st->owned)
645
+ git_stream_free(st->io);
646
+
647
+ git__free(st);
648
+ }
649
+
650
+ static int schannel_stream_wrap(
651
+ git_stream **out,
652
+ git_stream *in,
653
+ const char *host,
654
+ int owned)
655
+ {
656
+ schannel_stream *st;
657
+
658
+ st = git__calloc(1, sizeof(schannel_stream));
659
+ GIT_ERROR_CHECK_ALLOC(st);
660
+
661
+ st->io = in;
662
+ st->owned = owned;
663
+
664
+ if (git_utf8_to_16_alloc(&st->host_w, host) < 0) {
665
+ git__free(st);
666
+ return -1;
667
+ }
668
+
669
+ st->parent.version = GIT_STREAM_VERSION;
670
+ st->parent.encrypted = 1;
671
+ st->parent.proxy_support = git_stream_supports_proxy(st->io);
672
+ st->parent.connect = schannel_connect;
673
+ st->parent.certificate = schannel_certificate;
674
+ st->parent.set_proxy = schannel_set_proxy;
675
+ st->parent.read = schannel_read;
676
+ st->parent.write = schannel_write;
677
+ st->parent.close = schannel_close;
678
+ st->parent.free = schannel_free;
679
+
680
+ *out = (git_stream *)st;
681
+ return 0;
682
+ }
683
+
684
+ extern int git_schannel_stream_new(
685
+ git_stream **out,
686
+ const char *host,
687
+ const char *port)
688
+ {
689
+ git_stream *stream;
690
+ int error;
691
+
692
+ GIT_ASSERT_ARG(out);
693
+ GIT_ASSERT_ARG(host);
694
+ GIT_ASSERT_ARG(port);
695
+
696
+ if ((error = git_socket_stream_new(&stream, host, port)) < 0)
697
+ return error;
698
+
699
+ if ((error = schannel_stream_wrap(out, stream, host, 1)) < 0) {
700
+ git_stream_close(stream);
701
+ git_stream_free(stream);
702
+ }
703
+
704
+ return error;
705
+ }
706
+
707
+ extern int git_schannel_stream_wrap(
708
+ git_stream **out,
709
+ git_stream *in,
710
+ const char *host)
711
+ {
712
+ return schannel_stream_wrap(out, in, host, 0);
713
+ }
714
+
715
+ #endif