xref: /aosp_15_r20/external/cronet/net/http/mock_gssapi_library_posix.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2010 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/http/mock_gssapi_library_posix.h"
6 
7 #include "base/strings/string_util.h"
8 #include "base/strings/stringprintf.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 
11 namespace net {
12 
13 namespace test {
14 
15 struct GssNameMockImpl {
16   std::string name;
17   gss_OID_desc name_type;
18 
FromGssNamenet::test::GssNameMockImpl19   static GssNameMockImpl* FromGssName(gss_name_t name) {
20     return reinterpret_cast<GssNameMockImpl*>(name);
21   }
22 
ToGssNamenet::test::GssNameMockImpl23   static gss_name_t ToGssName(GssNameMockImpl* name) {
24     return reinterpret_cast<gss_name_t>(name);
25   }
26 };
27 
28 }  // namespace test
29 
30 namespace {
31 
32 // gss_OID helpers.
33 // NOTE: gss_OID's do not own the data they point to, which should be static.
ClearOid(gss_OID dest)34 void ClearOid(gss_OID dest) {
35   if (!dest)
36     return;
37   dest->length = 0;
38   dest->elements = nullptr;
39 }
40 
SetOid(gss_OID dest,const void * src,size_t length)41 void SetOid(gss_OID dest, const void* src, size_t length) {
42   if (!dest)
43     return;
44   ClearOid(dest);
45   if (!src)
46     return;
47   dest->length = length;
48   if (length)
49     dest->elements = const_cast<void*>(src);
50 }
51 
CopyOid(gss_OID dest,const gss_OID_desc * src)52 void CopyOid(gss_OID dest, const gss_OID_desc* src) {
53   if (!dest)
54     return;
55   ClearOid(dest);
56   if (!src)
57     return;
58   SetOid(dest, src->elements, src->length);
59 }
60 
61 // gss_buffer_t helpers.
ClearBuffer(gss_buffer_t dest)62 void ClearBuffer(gss_buffer_t dest) {
63   if (!dest)
64     return;
65   dest->length = 0;
66   if (dest->value) {
67     delete[] reinterpret_cast<char*>(dest->value);
68     dest->value = nullptr;
69   }
70 }
71 
SetBuffer(gss_buffer_t dest,const void * src,size_t length)72 void SetBuffer(gss_buffer_t dest, const void* src, size_t length) {
73   if (!dest)
74     return;
75   ClearBuffer(dest);
76   if (!src)
77     return;
78   dest->length = length;
79   if (length) {
80     dest->value = new char[length];
81     memcpy(dest->value, src, length);
82   }
83 }
84 
CopyBuffer(gss_buffer_t dest,const gss_buffer_t src)85 void CopyBuffer(gss_buffer_t dest, const gss_buffer_t src) {
86   if (!dest)
87     return;
88   ClearBuffer(dest);
89   if (!src)
90     return;
91   SetBuffer(dest, src->value, src->length);
92 }
93 
BufferToString(const gss_buffer_t src)94 std::string BufferToString(const gss_buffer_t src) {
95   std::string dest;
96   if (!src)
97     return dest;
98   const char* string = reinterpret_cast<char*>(src->value);
99   dest.assign(string, src->length);
100   return dest;
101 }
102 
BufferFromString(const std::string & src,gss_buffer_t dest)103 void BufferFromString(const std::string& src, gss_buffer_t dest) {
104   if (!dest)
105     return;
106   SetBuffer(dest, src.c_str(), src.length());
107 }
108 
109 // gss_name_t helpers.
ClearName(gss_name_t dest)110 void ClearName(gss_name_t dest) {
111   if (!dest)
112     return;
113   auto* name = test::GssNameMockImpl::FromGssName(dest);
114   name->name.clear();
115   ClearOid(&name->name_type);
116 }
117 
SetName(gss_name_t dest,const void * src,size_t length)118 void SetName(gss_name_t dest, const void* src, size_t length) {
119   if (!dest)
120     return;
121   ClearName(dest);
122   if (!src)
123     return;
124   auto* name = test::GssNameMockImpl::FromGssName(dest);
125   name->name.assign(reinterpret_cast<const char*>(src), length);
126 }
127 
NameFromString(const std::string & src)128 gss_name_t NameFromString(const std::string& src) {
129   gss_name_t dest = test::GssNameMockImpl::ToGssName(
130       new test::GssNameMockImpl{"", {0, nullptr}});
131   SetName(dest, src.c_str(), src.length());
132   return dest;
133 }
134 
135 }  // namespace
136 
137 namespace test {
138 
GssContextMockImpl()139 GssContextMockImpl::GssContextMockImpl()
140   : lifetime_rec(0),
141     ctx_flags(0),
142     locally_initiated(0),
143     open(0) {
144   ClearOid(&mech_type);
145 }
146 
GssContextMockImpl(const GssContextMockImpl & other)147 GssContextMockImpl::GssContextMockImpl(const GssContextMockImpl& other)
148   : src_name(other.src_name),
149     targ_name(other.targ_name),
150     lifetime_rec(other.lifetime_rec),
151     ctx_flags(other.ctx_flags),
152     locally_initiated(other.locally_initiated),
153     open(other.open) {
154   CopyOid(&mech_type, &other.mech_type);
155 }
156 
GssContextMockImpl(const char * src_name_in,const char * targ_name_in,OM_uint32 lifetime_rec_in,const gss_OID_desc & mech_type_in,OM_uint32 ctx_flags_in,int locally_initiated_in,int open_in)157 GssContextMockImpl::GssContextMockImpl(const char* src_name_in,
158                                        const char* targ_name_in,
159                                        OM_uint32 lifetime_rec_in,
160                                        const gss_OID_desc& mech_type_in,
161                                        OM_uint32 ctx_flags_in,
162                                        int locally_initiated_in,
163                                        int open_in)
164     : src_name(src_name_in ? src_name_in : ""),
165       targ_name(targ_name_in ? targ_name_in : ""),
166       lifetime_rec(lifetime_rec_in),
167       ctx_flags(ctx_flags_in),
168       locally_initiated(locally_initiated_in),
169       open(open_in) {
170   CopyOid(&mech_type, &mech_type_in);
171 }
172 
~GssContextMockImpl()173 GssContextMockImpl::~GssContextMockImpl() {
174   ClearOid(&mech_type);
175 }
176 
Assign(const GssContextMockImpl & other)177 void GssContextMockImpl::Assign(
178     const GssContextMockImpl& other) {
179   if (&other == this)
180     return;
181   src_name = other.src_name;
182   targ_name = other.targ_name;
183   lifetime_rec = other.lifetime_rec;
184   CopyOid(&mech_type, &other.mech_type);
185   ctx_flags = other.ctx_flags;
186   locally_initiated = other.locally_initiated;
187   open = other.open;
188 }
189 
SecurityContextQuery()190 MockGSSAPILibrary::SecurityContextQuery::SecurityContextQuery()
191     : expected_package(),
192       response_code(0),
193       minor_response_code(0),
194       context_info() {
195   expected_input_token.length = 0;
196   expected_input_token.value = nullptr;
197   output_token.length = 0;
198   output_token.value = nullptr;
199 }
200 
SecurityContextQuery(const std::string & in_expected_package,OM_uint32 in_response_code,OM_uint32 in_minor_response_code,const test::GssContextMockImpl & in_context_info,const char * in_expected_input_token,const char * in_output_token)201 MockGSSAPILibrary::SecurityContextQuery::SecurityContextQuery(
202     const std::string& in_expected_package,
203     OM_uint32 in_response_code,
204     OM_uint32 in_minor_response_code,
205     const test::GssContextMockImpl& in_context_info,
206     const char* in_expected_input_token,
207     const char* in_output_token)
208     : expected_package(in_expected_package),
209       response_code(in_response_code),
210       minor_response_code(in_minor_response_code),
211       context_info(in_context_info) {
212   if (in_expected_input_token) {
213     expected_input_token.length = strlen(in_expected_input_token);
214     expected_input_token.value = const_cast<char*>(in_expected_input_token);
215   } else {
216     expected_input_token.length = 0;
217     expected_input_token.value = nullptr;
218   }
219 
220   if (in_output_token) {
221     output_token.length = strlen(in_output_token);
222     output_token.value = const_cast<char*>(in_output_token);
223   } else {
224     output_token.length = 0;
225     output_token.value = nullptr;
226   }
227 }
228 
229 MockGSSAPILibrary::SecurityContextQuery::SecurityContextQuery(
230     const SecurityContextQuery& other) = default;
231 
232 MockGSSAPILibrary::SecurityContextQuery::~SecurityContextQuery() = default;
233 
234 MockGSSAPILibrary::MockGSSAPILibrary() = default;
235 
236 MockGSSAPILibrary::~MockGSSAPILibrary() = default;
237 
ExpectSecurityContext(const std::string & expected_package,OM_uint32 response_code,OM_uint32 minor_response_code,const GssContextMockImpl & context_info,const gss_buffer_desc & expected_input_token,const gss_buffer_desc & output_token)238 void MockGSSAPILibrary::ExpectSecurityContext(
239     const std::string& expected_package,
240     OM_uint32 response_code,
241     OM_uint32 minor_response_code,
242     const GssContextMockImpl& context_info,
243     const gss_buffer_desc& expected_input_token,
244     const gss_buffer_desc& output_token) {
245   SecurityContextQuery security_query;
246   security_query.expected_package = expected_package;
247   security_query.response_code = response_code;
248   security_query.minor_response_code = minor_response_code;
249   security_query.context_info.Assign(context_info);
250   security_query.expected_input_token = expected_input_token;
251   security_query.output_token = output_token;
252   expected_security_queries_.push_back(security_query);
253 }
254 
Init(const NetLogWithSource &)255 bool MockGSSAPILibrary::Init(const NetLogWithSource&) {
256   return true;
257 }
258 
259 // These methods match the ones in the GSSAPI library.
import_name(OM_uint32 * minor_status,const gss_buffer_t input_name_buffer,const gss_OID input_name_type,gss_name_t * output_name)260 OM_uint32 MockGSSAPILibrary::import_name(
261       OM_uint32* minor_status,
262       const gss_buffer_t input_name_buffer,
263       const gss_OID input_name_type,
264       gss_name_t* output_name) {
265   if (minor_status)
266     *minor_status = 0;
267   if (!output_name)
268     return GSS_S_BAD_NAME;
269   if (!input_name_buffer)
270     return GSS_S_CALL_BAD_STRUCTURE;
271   if (!input_name_type)
272     return GSS_S_BAD_NAMETYPE;
273   GssNameMockImpl* output = new GssNameMockImpl;
274   if (output == nullptr)
275     return GSS_S_FAILURE;
276   output->name_type.length = 0;
277   output->name_type.elements = nullptr;
278 
279   // Save the data.
280   output->name = BufferToString(input_name_buffer);
281   CopyOid(&output->name_type, input_name_type);
282   *output_name = test::GssNameMockImpl::ToGssName(output);
283 
284   return GSS_S_COMPLETE;
285 }
286 
release_name(OM_uint32 * minor_status,gss_name_t * input_name)287 OM_uint32 MockGSSAPILibrary::release_name(
288       OM_uint32* minor_status,
289       gss_name_t* input_name) {
290   if (minor_status)
291     *minor_status = 0;
292   if (!input_name)
293     return GSS_S_BAD_NAME;
294   if (!*input_name)
295     return GSS_S_COMPLETE;
296   GssNameMockImpl* name = GssNameMockImpl::FromGssName(*input_name);
297   ClearName(*input_name);
298   delete name;
299   *input_name = GSS_C_NO_NAME;
300   return GSS_S_COMPLETE;
301 }
302 
release_buffer(OM_uint32 * minor_status,gss_buffer_t buffer)303 OM_uint32 MockGSSAPILibrary::release_buffer(
304       OM_uint32* minor_status,
305       gss_buffer_t buffer) {
306   if (minor_status)
307     *minor_status = 0;
308   if (!buffer)
309     return GSS_S_BAD_NAME;
310   ClearBuffer(buffer);
311   return GSS_S_COMPLETE;
312 }
313 
display_name(OM_uint32 * minor_status,const gss_name_t input_name,gss_buffer_t output_name_buffer,gss_OID * output_name_type)314 OM_uint32 MockGSSAPILibrary::display_name(
315     OM_uint32* minor_status,
316     const gss_name_t input_name,
317     gss_buffer_t output_name_buffer,
318     gss_OID* output_name_type) {
319   if (minor_status)
320     *minor_status = 0;
321   if (!input_name)
322     return GSS_S_BAD_NAME;
323   if (!output_name_buffer)
324     return GSS_S_CALL_BAD_STRUCTURE;
325   if (!output_name_type)
326     return GSS_S_CALL_BAD_STRUCTURE;
327   GssNameMockImpl* internal_name = GssNameMockImpl::FromGssName(input_name);
328   std::string name = internal_name->name;
329   BufferFromString(name, output_name_buffer);
330   if (output_name_type) {
331     *output_name_type =
332         internal_name ? &internal_name->name_type : GSS_C_NO_OID;
333   }
334   return GSS_S_COMPLETE;
335 }
336 
display_status(OM_uint32 * minor_status,OM_uint32 status_value,int status_type,const gss_OID mech_type,OM_uint32 * message_context,gss_buffer_t status_string)337 OM_uint32 MockGSSAPILibrary::display_status(
338       OM_uint32* minor_status,
339       OM_uint32 status_value,
340       int status_type,
341       const gss_OID mech_type,
342       OM_uint32* message_context,
343       gss_buffer_t status_string) {
344   OM_uint32 rv = GSS_S_COMPLETE;
345   *minor_status = 0;
346   std::string msg;
347   switch (static_cast<DisplayStatusSpecials>(status_value)) {
348     case DisplayStatusSpecials::MultiLine:
349       msg = base::StringPrintf("Line %u for status %u", ++*message_context,
350                                status_value);
351       if (*message_context >= 5u)
352         *message_context = 0u;
353       break;
354 
355     case DisplayStatusSpecials::InfiniteLines:
356       msg = base::StringPrintf("Line %u for status %u", ++*message_context,
357                                status_value);
358       break;
359 
360     case DisplayStatusSpecials::Fail:
361       rv = GSS_S_BAD_MECH;
362       msg = "You should not see this";
363       EXPECT_EQ(*message_context, 0u);
364       break;
365 
366     case DisplayStatusSpecials::EmptyMessage:
367       EXPECT_EQ(*message_context, 0u);
368       break;
369 
370     case DisplayStatusSpecials::UninitalizedBuffer:
371       EXPECT_EQ(*message_context, 0u);
372       return GSS_S_COMPLETE;
373 
374     case DisplayStatusSpecials::InvalidUtf8:
375       msg = "\xff\xff\xff";
376       EXPECT_EQ(*message_context, 0u);
377       break;
378 
379     default:
380       msg = base::StringPrintf("Value: %u, Type %u", status_value, status_type);
381       EXPECT_EQ(*message_context, 0u);
382   }
383   BufferFromString(msg, status_string);
384   return rv;
385 }
386 
init_sec_context(OM_uint32 * minor_status,const gss_cred_id_t initiator_cred_handle,gss_ctx_id_t * context_handle,const gss_name_t target_name,const gss_OID mech_type,OM_uint32 req_flags,OM_uint32 time_req,const gss_channel_bindings_t input_chan_bindings,const gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec)387 OM_uint32 MockGSSAPILibrary::init_sec_context(
388       OM_uint32* minor_status,
389       const gss_cred_id_t initiator_cred_handle,
390       gss_ctx_id_t* context_handle,
391       const gss_name_t target_name,
392       const gss_OID mech_type,
393       OM_uint32 req_flags,
394       OM_uint32 time_req,
395       const gss_channel_bindings_t input_chan_bindings,
396       const gss_buffer_t input_token,
397       gss_OID* actual_mech_type,
398       gss_buffer_t output_token,
399       OM_uint32* ret_flags,
400       OM_uint32* time_rec) {
401   if (minor_status)
402     *minor_status = 0;
403   if (!context_handle)
404     return GSS_S_CALL_BAD_STRUCTURE;
405   GssContextMockImpl** internal_context_handle =
406       reinterpret_cast<test::GssContextMockImpl**>(context_handle);
407   // Create it if necessary.
408   if (!*internal_context_handle) {
409     *internal_context_handle = new GssContextMockImpl;
410   }
411   EXPECT_TRUE(*internal_context_handle);
412   GssContextMockImpl& context = **internal_context_handle;
413   if (expected_security_queries_.empty()) {
414     return GSS_S_UNAVAILABLE;
415   }
416   SecurityContextQuery security_query = expected_security_queries_.front();
417   expected_security_queries_.pop_front();
418   EXPECT_EQ(std::string("Negotiate"), security_query.expected_package);
419   OM_uint32 major_status = security_query.response_code;
420   if (minor_status)
421     *minor_status = security_query.minor_response_code;
422   context.src_name = security_query.context_info.src_name;
423   context.targ_name = security_query.context_info.targ_name;
424   context.lifetime_rec = security_query.context_info.lifetime_rec;
425   CopyOid(&context.mech_type, &security_query.context_info.mech_type);
426   context.ctx_flags = security_query.context_info.ctx_flags;
427   context.locally_initiated = security_query.context_info.locally_initiated;
428   context.open = security_query.context_info.open;
429   if (!input_token) {
430     EXPECT_FALSE(security_query.expected_input_token.length);
431   } else {
432     EXPECT_EQ(input_token->length, security_query.expected_input_token.length);
433     if (input_token->length) {
434       EXPECT_EQ(0, memcmp(input_token->value,
435                           security_query.expected_input_token.value,
436                           input_token->length));
437     }
438   }
439   CopyBuffer(output_token, &security_query.output_token);
440   if (actual_mech_type)
441     CopyOid(*actual_mech_type, mech_type);
442   if (ret_flags)
443     *ret_flags = req_flags;
444   return major_status;
445 }
446 
wrap_size_limit(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,OM_uint32 req_output_size,OM_uint32 * max_input_size)447 OM_uint32 MockGSSAPILibrary::wrap_size_limit(
448       OM_uint32* minor_status,
449       const gss_ctx_id_t context_handle,
450       int conf_req_flag,
451       gss_qop_t qop_req,
452       OM_uint32 req_output_size,
453       OM_uint32* max_input_size) {
454   if (minor_status)
455     *minor_status = 0;
456   ADD_FAILURE();
457   return GSS_S_UNAVAILABLE;
458 }
459 
delete_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_buffer_t output_token)460 OM_uint32 MockGSSAPILibrary::delete_sec_context(
461       OM_uint32* minor_status,
462       gss_ctx_id_t* context_handle,
463       gss_buffer_t output_token) {
464   if (minor_status)
465     *minor_status = 0;
466   if (!context_handle)
467     return GSS_S_CALL_BAD_STRUCTURE;
468   GssContextMockImpl** internal_context_handle =
469       reinterpret_cast<GssContextMockImpl**>(context_handle);
470   if (*internal_context_handle) {
471     delete *internal_context_handle;
472     *internal_context_handle = nullptr;
473   }
474   return GSS_S_COMPLETE;
475 }
476 
inquire_context(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,gss_name_t * src_name,gss_name_t * targ_name,OM_uint32 * lifetime_rec,gss_OID * mech_type,OM_uint32 * ctx_flags,int * locally_initiated,int * open)477 OM_uint32 MockGSSAPILibrary::inquire_context(
478     OM_uint32* minor_status,
479     const gss_ctx_id_t context_handle,
480     gss_name_t* src_name,
481     gss_name_t* targ_name,
482     OM_uint32* lifetime_rec,
483     gss_OID* mech_type,
484     OM_uint32* ctx_flags,
485     int* locally_initiated,
486     int* open) {
487   if (minor_status)
488     *minor_status = 0;
489   if (!context_handle)
490     return GSS_S_CALL_BAD_STRUCTURE;
491   GssContextMockImpl* internal_context_ptr =
492       reinterpret_cast<GssContextMockImpl*>(context_handle);
493   GssContextMockImpl& context = *internal_context_ptr;
494   if (src_name)
495     *src_name = NameFromString(context.src_name);
496   if (targ_name)
497     *targ_name = NameFromString(context.targ_name);
498   if (lifetime_rec)
499     *lifetime_rec = context.lifetime_rec;
500   if (mech_type)
501     CopyOid(*mech_type, &context.mech_type);
502   if (ctx_flags)
503     *ctx_flags = context.ctx_flags;
504   if (locally_initiated)
505     *locally_initiated = context.locally_initiated;
506   if (open)
507     *open = context.open;
508   return GSS_S_COMPLETE;
509 }
510 
GetLibraryNameForTesting()511 const std::string& MockGSSAPILibrary::GetLibraryNameForTesting() {
512   return library_name_;
513 }
514 
515 }  // namespace test
516 
517 }  // namespace net
518