/src/gss-ntlmssp/src/crypto.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2013-2022 Simo Sorce <simo@samba.org>, see COPYING for license */ |
2 | | |
3 | | #include <errno.h> |
4 | | #include <string.h> |
5 | | |
6 | | #include <openssl/des.h> |
7 | | #include <openssl/rc4.h> |
8 | | #include <openssl/evp.h> |
9 | | #include <openssl/rand.h> |
10 | | #include <zlib.h> |
11 | | |
12 | | #include "crypto.h" |
13 | | |
14 | | /* legacy provider with openssl 3.0 */ |
15 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
16 | | # include <openssl/provider.h> |
17 | | # include <openssl/crypto.h> |
18 | | #endif |
19 | | |
20 | | int RAND_BUFFER(struct ntlm_buffer *random) |
21 | 957 | { |
22 | 957 | int ret; |
23 | | |
24 | 957 | ret = RAND_bytes(random->data, random->length); |
25 | 957 | if (ret != 1) { |
26 | 0 | return ERR_CRYPTO; |
27 | 0 | } |
28 | 957 | return 0; |
29 | 957 | } |
30 | | |
31 | | int HMAC_MD5_IOV(struct ntlm_buffer *key, |
32 | | struct ntlm_iov *iov, |
33 | | struct ntlm_buffer *result) |
34 | 0 | { |
35 | 0 | EVP_MD_CTX* ctx = NULL; |
36 | 0 | EVP_PKEY* pkey = NULL; |
37 | 0 | size_t i; |
38 | 0 | int ret = 0; |
39 | |
|
40 | 0 | if (result->length != 16) return EINVAL; |
41 | | |
42 | 0 | pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key->data, key->length); |
43 | 0 | if (!pkey) { |
44 | 0 | ret = ERR_CRYPTO; |
45 | 0 | goto done; |
46 | 0 | } |
47 | | |
48 | 0 | ctx = EVP_MD_CTX_new(); |
49 | 0 | if (!ctx) { |
50 | 0 | ret = ERR_CRYPTO; |
51 | 0 | goto done; |
52 | 0 | } |
53 | | |
54 | 0 | ret = EVP_DigestSignInit(ctx, NULL, EVP_md5(), NULL, pkey); |
55 | 0 | if (ret != 1) { |
56 | 0 | ret = ERR_CRYPTO; |
57 | 0 | goto done; |
58 | 0 | } |
59 | | |
60 | 0 | for (i = 0; i < iov->num; i++) { |
61 | 0 | ret = EVP_DigestSignUpdate(ctx, iov->data[i]->data, |
62 | 0 | iov->data[i]->length); |
63 | 0 | if (ret != 1) { |
64 | 0 | ret = ERR_CRYPTO; |
65 | 0 | goto done; |
66 | 0 | } |
67 | 0 | } |
68 | | |
69 | 0 | ret = EVP_DigestSignFinal(ctx, result->data, &result->length); |
70 | 0 | if (ret != 1) { |
71 | 0 | ret = ERR_CRYPTO; |
72 | 0 | goto done; |
73 | 0 | } |
74 | | |
75 | 0 | ret = 0; |
76 | |
|
77 | 0 | done: |
78 | 0 | EVP_MD_CTX_free(ctx); |
79 | 0 | EVP_PKEY_free(pkey); |
80 | 0 | return ret; |
81 | 0 | } |
82 | | |
83 | | int HMAC_MD5(struct ntlm_buffer *key, |
84 | | struct ntlm_buffer *payload, |
85 | | struct ntlm_buffer *result) |
86 | 0 | { |
87 | 0 | struct ntlm_iov iov; |
88 | |
|
89 | 0 | iov.num = 1; |
90 | 0 | iov.data = &payload; |
91 | 0 | return HMAC_MD5_IOV(key, &iov, result); |
92 | 0 | } |
93 | | |
94 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
95 | | typedef struct ossl3_library_context { |
96 | | OSSL_LIB_CTX *libctx; |
97 | | OSSL_PROVIDER *legacy_provider; |
98 | | OSSL_PROVIDER *default_provider; |
99 | | } ossl3_context_t; |
100 | | |
101 | | static pthread_once_t global_ossl3_ctx_init = PTHREAD_ONCE_INIT; |
102 | | static ossl3_context_t *global_ossl3_ctx = NULL; |
103 | | |
104 | | static void init_global_ossl3_ctx(void) |
105 | | { |
106 | | ossl3_context_t *ctx = OPENSSL_malloc(sizeof(ossl3_context_t)); |
107 | | if (!ctx) return; |
108 | | |
109 | | ctx->libctx = OSSL_LIB_CTX_new(); |
110 | | if (!ctx->libctx) { |
111 | | OPENSSL_free(ctx); |
112 | | return; |
113 | | } |
114 | | |
115 | | /* Load both legacy and default provider as both may be needed */ |
116 | | /* if they fail keep going and an error will be raised when we try to |
117 | | * fetch the cipher later */ |
118 | | ctx->legacy_provider = OSSL_PROVIDER_load(ctx->libctx, "legacy"); |
119 | | ctx->default_provider = OSSL_PROVIDER_load(ctx->libctx, "default"); |
120 | | global_ossl3_ctx = ctx; |
121 | | } |
122 | | |
123 | | static ossl3_context_t *get_ossl3_ctx() |
124 | | { |
125 | | int ret; |
126 | | |
127 | | ret = pthread_once(&global_ossl3_ctx_init, init_global_ossl3_ctx); |
128 | | if (ret != 0) { |
129 | | return NULL; |
130 | | } |
131 | | |
132 | | return global_ossl3_ctx; |
133 | | } |
134 | | |
135 | | __attribute__((destructor)) |
136 | | static void free_ossl3_ctx() |
137 | | { |
138 | | ossl3_context_t *ctx = global_ossl3_ctx; |
139 | | if (ctx == NULL) return; |
140 | | if (ctx->legacy_provider) OSSL_PROVIDER_unload(ctx->legacy_provider); |
141 | | if (ctx->default_provider) OSSL_PROVIDER_unload(ctx->default_provider); |
142 | | if (ctx->libctx) OSSL_LIB_CTX_free(ctx->libctx); |
143 | | |
144 | | OPENSSL_free(ctx); |
145 | | } |
146 | | #endif |
147 | | |
148 | | static int mdx_hash(const EVP_MD *type, |
149 | | struct ntlm_buffer *payload, |
150 | | struct ntlm_buffer *result) |
151 | 0 | { |
152 | 0 | EVP_MD_CTX *ctx; |
153 | 0 | unsigned int len; |
154 | 0 | int ret; |
155 | |
|
156 | 0 | if (result->length != 16) return EINVAL; |
157 | | |
158 | 0 | ctx = EVP_MD_CTX_new(); |
159 | 0 | if (!ctx) { |
160 | 0 | ret = ERR_CRYPTO; |
161 | 0 | goto done; |
162 | 0 | } |
163 | | |
164 | 0 | EVP_MD_CTX_init(ctx); |
165 | 0 | ret = EVP_DigestInit_ex(ctx, type, NULL); |
166 | 0 | if (ret == 0) { |
167 | 0 | ret = ERR_CRYPTO; |
168 | 0 | goto done; |
169 | 0 | } |
170 | | |
171 | 0 | ret = EVP_DigestUpdate(ctx, payload->data, payload->length); |
172 | 0 | if (ret == 0) { |
173 | 0 | ret = ERR_CRYPTO; |
174 | 0 | goto done; |
175 | 0 | } |
176 | | |
177 | 0 | ret = EVP_DigestFinal_ex(ctx, result->data, &len); |
178 | 0 | if (ret == 0) { |
179 | 0 | ret = ERR_CRYPTO; |
180 | 0 | goto done; |
181 | 0 | } |
182 | | |
183 | 0 | ret = 0; |
184 | |
|
185 | 0 | done: |
186 | 0 | if (ctx) EVP_MD_CTX_free(ctx); |
187 | 0 | return ret; |
188 | 0 | } |
189 | | |
190 | | int MD4_HASH(struct ntlm_buffer *payload, |
191 | | struct ntlm_buffer *result) |
192 | 0 | { |
193 | | #if OPENSSL_VERSION_NUMBER >= 0x30000000L |
194 | | ossl3_context_t *ossl3_ctx = NULL; |
195 | | EVP_MD *md; |
196 | | int ret; |
197 | | |
198 | | ossl3_ctx = get_ossl3_ctx(); |
199 | | if (ossl3_ctx == NULL) { |
200 | | ret = ERR_CRYPTO; |
201 | | goto done; |
202 | | } |
203 | | |
204 | | md = EVP_MD_fetch(ossl3_ctx->libctx, "MD4", ""); |
205 | | if (md == NULL) { |
206 | | ret = ERR_CRYPTO; |
207 | | goto done; |
208 | | } |
209 | | |
210 | | ret = mdx_hash(md, payload, result); |
211 | | |
212 | | done: |
213 | | return ret; |
214 | | #else |
215 | 0 | return mdx_hash(EVP_md4(), payload, result); |
216 | 0 | #endif |
217 | |
|
218 | 0 | } |
219 | | |
220 | | int MD5_HASH(struct ntlm_buffer *payload, |
221 | | struct ntlm_buffer *result) |
222 | 0 | { |
223 | 0 | return mdx_hash(EVP_md5(), payload, result); |
224 | 0 | } |
225 | | |
226 | | struct ntlm_rc4_handle { |
227 | | RC4_KEY key; |
228 | | }; |
229 | | |
230 | | int RC4_INIT(struct ntlm_buffer *rc4_key, |
231 | | enum ntlm_cipher_mode mode, |
232 | | struct ntlm_rc4_handle **out) |
233 | 0 | { |
234 | 0 | struct ntlm_rc4_handle *handle; |
235 | |
|
236 | 0 | handle = malloc(sizeof(struct ntlm_rc4_handle)); |
237 | 0 | if (!handle) return ENOMEM; |
238 | | |
239 | 0 | RC4_set_key(&handle->key, rc4_key->length, rc4_key->data); |
240 | |
|
241 | 0 | *out = handle; |
242 | 0 | return 0; |
243 | 0 | } |
244 | | |
245 | | int RC4_UPDATE(struct ntlm_rc4_handle *handle, |
246 | | struct ntlm_buffer *in, struct ntlm_buffer *out) |
247 | 0 | { |
248 | 0 | if (out->length < in->length) return EINVAL; |
249 | | |
250 | 0 | if (in->length > 0) { |
251 | 0 | RC4(&handle->key, in->length, in->data, out->data); |
252 | 0 | } |
253 | |
|
254 | 0 | out->length = in->length; |
255 | 0 | return 0; |
256 | 0 | } |
257 | | |
258 | | void RC4_FREE(struct ntlm_rc4_handle **handle) |
259 | 2.29k | { |
260 | 2.29k | if (!handle || !*handle) return; |
261 | 0 | safezero((uint8_t *)(&((*handle)->key)), sizeof(RC4_KEY)); |
262 | 0 | safefree(*handle); |
263 | 0 | } |
264 | | |
265 | | int RC4_EXPORT(struct ntlm_rc4_handle *handle, struct ntlm_buffer *out) |
266 | 0 | { |
267 | 0 | RC4_INT *data = (RC4_INT *)out->data; |
268 | 0 | int len = 258 * sizeof(RC4_INT); |
269 | |
|
270 | 0 | if (out->length < len) return EINVAL; |
271 | | |
272 | 0 | data[0] = handle->key.x; |
273 | 0 | data[1] = handle->key.y; |
274 | 0 | memcpy(&data[2], handle->key.data, sizeof(RC4_INT) * 256); |
275 | 0 | out->length = len; |
276 | 0 | return 0; |
277 | 0 | } |
278 | | |
279 | | int RC4_IMPORT(struct ntlm_rc4_handle **_handle, struct ntlm_buffer *in) |
280 | 0 | { |
281 | 0 | struct ntlm_rc4_handle *handle; |
282 | 0 | RC4_INT *data = (RC4_INT *)in->data; |
283 | 0 | int len = 258 * sizeof(RC4_INT); |
284 | |
|
285 | 0 | if (in->length != len) return EINVAL; |
286 | | |
287 | 0 | handle = malloc(sizeof(struct ntlm_rc4_handle)); |
288 | 0 | if (!handle) return ENOMEM; |
289 | | |
290 | 0 | handle->key.x = data[0]; |
291 | 0 | handle->key.y = data[1]; |
292 | 0 | memcpy(handle->key.data, &data[2], sizeof(RC4_INT) * 256); |
293 | |
|
294 | 0 | *_handle = handle; |
295 | 0 | return 0; |
296 | 0 | } |
297 | | |
298 | | int RC4K(struct ntlm_buffer *key, |
299 | | enum ntlm_cipher_mode mode, |
300 | | struct ntlm_buffer *payload, |
301 | | struct ntlm_buffer *result) |
302 | 0 | { |
303 | 0 | struct ntlm_rc4_handle *handle; |
304 | 0 | int ret; |
305 | |
|
306 | 0 | if (result->length < payload->length) return EINVAL; |
307 | | |
308 | 0 | ret = RC4_INIT(key, mode, &handle); |
309 | 0 | if (ret) return ret; |
310 | | |
311 | 0 | ret = RC4_UPDATE(handle, payload, result); |
312 | |
|
313 | 0 | RC4_FREE(&handle); |
314 | 0 | return ret; |
315 | 0 | } |
316 | | |
317 | | int WEAK_DES(struct ntlm_buffer *key, |
318 | | struct ntlm_buffer *payload, |
319 | | struct ntlm_buffer *result) |
320 | 0 | { |
321 | 0 | DES_key_schedule schedule; |
322 | 0 | DES_cblock key8; |
323 | |
|
324 | 0 | if ((key->length != 7) || |
325 | 0 | (payload->length != 8) || |
326 | 0 | (result->length != 8)) { |
327 | 0 | return EINVAL; |
328 | 0 | } |
329 | | |
330 | | /* Undocumented shuffle needed before calling DES_set_key_unchecked */ |
331 | 0 | key8[0] = key->data[0]; |
332 | 0 | key8[1] = (key->data[0] << 7) | (key->data[1] >> 1); |
333 | 0 | key8[2] = (key->data[1] << 6) | (key->data[2] >> 2); |
334 | 0 | key8[3] = (key->data[2] << 5) | (key->data[3] >> 3); |
335 | 0 | key8[4] = (key->data[3] << 4) | (key->data[4] >> 4); |
336 | 0 | key8[5] = (key->data[4] << 3) | (key->data[5] >> 5); |
337 | 0 | key8[6] = (key->data[5] << 2) | (key->data[6] >> 6); |
338 | 0 | key8[7] = (key->data[6] << 1); |
339 | |
|
340 | 0 | DES_set_key_unchecked(&key8, &schedule); |
341 | 0 | DES_ecb_encrypt((DES_cblock *)payload->data, |
342 | 0 | (DES_cblock *)result->data, &schedule, 1); |
343 | 0 | return 0; |
344 | 0 | } |
345 | | |
346 | | int DESL(struct ntlm_buffer *key, |
347 | | struct ntlm_buffer *payload, |
348 | | struct ntlm_buffer *result) |
349 | 0 | { |
350 | 0 | uint8_t buf7[7]; |
351 | 0 | struct ntlm_buffer key7; |
352 | 0 | struct ntlm_buffer res8; |
353 | |
|
354 | 0 | if ((key->length != 16) || |
355 | 0 | (payload->length != 8) || |
356 | 0 | (result->length != 24)) { |
357 | 0 | return EINVAL; |
358 | 0 | } |
359 | | |
360 | | /* part 1 */ |
361 | 0 | key7.data = key->data; |
362 | 0 | key7.length = 7; |
363 | 0 | res8.data = result->data; |
364 | 0 | res8.length = 8; |
365 | 0 | WEAK_DES(&key7, payload, &res8); |
366 | | /* part 2 */ |
367 | 0 | key7.data = &key->data[7]; |
368 | 0 | key7.length = 7; |
369 | 0 | res8.data = &result->data[8]; |
370 | 0 | res8.length = 8; |
371 | 0 | WEAK_DES(&key7, payload, &res8); |
372 | | /* part 3 */ |
373 | 0 | memcpy(buf7, &key->data[14], 2); |
374 | 0 | memset(&buf7[2], 0, 5); |
375 | 0 | key7.data = buf7; |
376 | 0 | key7.length = 7; |
377 | 0 | res8.data = &result->data[16]; |
378 | 0 | res8.length = 8; |
379 | 0 | WEAK_DES(&key7, payload, &res8); |
380 | |
|
381 | 0 | return 0; |
382 | 0 | } |
383 | | |
384 | | uint32_t CRC32(uint32_t crc, struct ntlm_buffer *payload) |
385 | 0 | { |
386 | 0 | return crc32(crc, payload->data, payload->length); |
387 | 0 | } |