Coverage Report

Created: 2025-11-11 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/Botan-3.4.0/src/lib/ffi/ffi_srp6.cpp
Line
Count
Source
1
/*
2
* (C) 2022 Rostyslav Khudolii
3
*     2023 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/ffi.h>
9
10
#include <botan/internal/ffi_rng.h>
11
#include <botan/internal/ffi_util.h>
12
13
#if defined(BOTAN_HAS_SRP6)
14
   #include <botan/bigint.h>
15
   #include <botan/dl_group.h>
16
   #include <botan/rng.h>
17
   #include <botan/srp6.h>
18
   #include <botan/symkey.h>
19
#endif
20
21
extern "C" {
22
23
using namespace Botan_FFI;
24
25
#if defined(BOTAN_HAS_SRP6)
26
BOTAN_FFI_DECLARE_STRUCT(botan_srp6_server_session_struct, Botan::SRP6_Server_Session, 0x44F7425F);
27
#else
28
BOTAN_FFI_DECLARE_DUMMY_STRUCT(botan_srp6_server_session_struct, 0x44F7425F);
29
#endif
30
31
0
int botan_srp6_server_session_init(botan_srp6_server_session_t* srp6) {
32
#if defined(BOTAN_HAS_SRP6)
33
   return ffi_guard_thunk(__func__, [=]() -> int {
34
      *srp6 = new botan_srp6_server_session_struct(std::make_unique<Botan::SRP6_Server_Session>());
35
      return BOTAN_FFI_SUCCESS;
36
   });
37
#else
38
0
   BOTAN_UNUSED(srp6);
39
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
40
0
#endif
41
0
}
42
43
0
int botan_srp6_server_session_destroy(botan_srp6_server_session_t srp6) {
44
0
   return BOTAN_FFI_CHECKED_DELETE(srp6);
45
0
}
46
47
0
int botan_srp6_group_size(const char* group_id, size_t* group_p_bytes) {
48
#if defined(BOTAN_HAS_SRP6)
49
   if(group_id == nullptr || group_p_bytes == nullptr) {
50
      return BOTAN_FFI_ERROR_NULL_POINTER;
51
   }
52
53
   return ffi_guard_thunk(__func__, [=]() -> int {
54
      Botan::DL_Group group(group_id);
55
      *group_p_bytes = group.p_bytes();
56
      return BOTAN_FFI_SUCCESS;
57
   });
58
#else
59
0
   BOTAN_UNUSED(group_id, group_p_bytes);
60
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
61
0
#endif
62
0
}
63
64
int botan_srp6_server_session_step1(botan_srp6_server_session_t srp6,
65
                                    const uint8_t* verifier,
66
                                    size_t verifier_len,
67
                                    const char* group_id,
68
                                    const char* hash_id,
69
                                    botan_rng_t rng_obj,
70
                                    uint8_t b_pub[],
71
0
                                    size_t* b_pub_len) {
72
#if defined(BOTAN_HAS_SRP6)
73
   return BOTAN_FFI_VISIT(srp6, [=](auto& s) -> int {
74
      if(!verifier || !group_id || !hash_id || !rng_obj) {
75
         return BOTAN_FFI_ERROR_NULL_POINTER;
76
      }
77
      try {
78
         Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
79
         auto v_bn = Botan::BigInt::decode(verifier, verifier_len);
80
         auto b_pub_bn = s.step1(v_bn, group_id, hash_id, rng);
81
         return write_vec_output(b_pub, b_pub_len, Botan::BigInt::encode(b_pub_bn));
82
      } catch(Botan::Decoding_Error&) {
83
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
84
      } catch(Botan::Lookup_Error&) {
85
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
86
      }
87
   });
88
#else
89
0
   BOTAN_UNUSED(srp6, verifier, verifier_len, group_id, hash_id, rng_obj, b_pub, b_pub_len);
90
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
91
0
#endif
92
0
}
93
94
int botan_srp6_server_session_step2(
95
0
   botan_srp6_server_session_t srp6, const uint8_t a[], size_t a_len, uint8_t key[], size_t* key_len) {
96
#if defined(BOTAN_HAS_SRP6)
97
   return BOTAN_FFI_VISIT(srp6, [=](auto& s) -> int {
98
      if(!a) {
99
         return BOTAN_FFI_ERROR_NULL_POINTER;
100
      }
101
      try {
102
         Botan::BigInt a_bn = Botan::BigInt::decode(a, a_len);
103
         auto key_sk = s.step2(a_bn);
104
         return write_vec_output(key, key_len, key_sk.bits_of());
105
      } catch(Botan::Decoding_Error&) {
106
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
107
      }
108
   });
109
#else
110
0
   BOTAN_UNUSED(srp6, a, a_len, key, key_len);
111
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
112
0
#endif
113
0
}
114
115
int botan_srp6_generate_verifier(const char* username,
116
                                 const char* password,
117
                                 const uint8_t salt[],
118
                                 size_t salt_len,
119
                                 const char* group_id,
120
                                 const char* hash_id,
121
                                 uint8_t verifier[],
122
0
                                 size_t* verifier_len) {
123
#if defined(BOTAN_HAS_SRP6)
124
   return ffi_guard_thunk(__func__, [=]() -> int {
125
      if(!username || !password || !salt || !group_id || !hash_id) {
126
         return BOTAN_FFI_ERROR_NULL_POINTER;
127
      }
128
      try {
129
         std::vector<uint8_t> salt_vec(salt, salt + salt_len);
130
         auto verifier_bn = Botan::srp6_generate_verifier(username, password, salt_vec, group_id, hash_id);
131
         return write_vec_output(verifier, verifier_len, Botan::BigInt::encode(verifier_bn));
132
      } catch(Botan::Lookup_Error&) {
133
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
134
      }
135
   });
136
#else
137
0
   BOTAN_UNUSED(username, password, group_id, hash_id);
138
0
   BOTAN_UNUSED(salt, salt_len, verifier, verifier_len);
139
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
140
0
#endif
141
0
}
142
143
int botan_srp6_client_agree(const char* identity,
144
                            const char* password,
145
                            const char* group_id,
146
                            const char* hash_id,
147
                            const uint8_t salt[],
148
                            size_t salt_len,
149
                            const uint8_t b[],
150
                            size_t b_len,
151
                            botan_rng_t rng_obj,
152
                            uint8_t A[],
153
                            size_t* A_len,
154
                            uint8_t K[],
155
0
                            size_t* K_len) {
156
#if defined(BOTAN_HAS_SRP6)
157
   return ffi_guard_thunk(__func__, [=]() -> int {
158
      if(!identity || !password || !salt || !group_id || !hash_id || !b || !rng_obj) {
159
         return BOTAN_FFI_ERROR_NULL_POINTER;
160
      }
161
      try {
162
         std::vector<uint8_t> saltv(salt, salt + salt_len);
163
         Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
164
         auto b_bn = Botan::BigInt::decode(b, b_len);
165
         auto [A_bn, K_sk] = Botan::srp6_client_agree(identity, password, group_id, hash_id, saltv, b_bn, rng);
166
         auto ret_a = write_vec_output(A, A_len, Botan::BigInt::encode(A_bn));
167
         auto ret_k = write_vec_output(K, K_len, K_sk.bits_of());
168
         if(ret_a != BOTAN_FFI_SUCCESS) {
169
            return ret_a;
170
         }
171
         if(ret_k != BOTAN_FFI_SUCCESS) {
172
            return ret_k;
173
         }
174
         return BOTAN_FFI_SUCCESS;
175
      } catch(Botan::Lookup_Error&) {
176
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
177
      }
178
   });
179
#else
180
0
   BOTAN_UNUSED(identity, password, group_id, hash_id, rng_obj);
181
0
   BOTAN_UNUSED(salt, salt_len, b, b_len, A, A_len, K, K_len);
182
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
183
0
#endif
184
0
}
185
}