1 /* ppp-crypto.c - Generic API for access to crypto/digest functions.
2 *
3 * Copyright (c) 2022 Eivind Næss. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * 3. The name(s) of the authors of this software must not be used to
18 * endorse or promote products derived from this software without
19 * prior written permission.
20 *
21 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
22 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
23 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
24 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
25 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
26 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
27 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28 */
29
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stdio.h>
38
39 #include "pppd.h"
40 #include "crypto.h"
41 #include "crypto-priv.h"
42
43 #ifdef PPP_WITH_OPENSSL
44 #include <openssl/opensslv.h>
45 #include <openssl/err.h>
46
47 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
48 #include <openssl/provider.h>
49 struct crypto_ctx {
50
51 OSSL_PROVIDER *legacy;
52 OSSL_PROVIDER *provider;
53 } g_crypto_ctx;
54 #endif
55 #endif
56
PPP_MD_CTX_new()57 PPP_MD_CTX *PPP_MD_CTX_new()
58 {
59 return (PPP_MD_CTX*) calloc(1, sizeof(PPP_MD_CTX));
60 }
61
PPP_MD_CTX_free(PPP_MD_CTX * ctx)62 void PPP_MD_CTX_free(PPP_MD_CTX* ctx)
63 {
64 if (ctx) {
65 if (ctx->md.clean_fn) {
66 ctx->md.clean_fn(ctx);
67 }
68 free(ctx);
69 }
70 }
71
PPP_DigestInit(PPP_MD_CTX * ctx,const PPP_MD * type)72 int PPP_DigestInit(PPP_MD_CTX *ctx, const PPP_MD *type)
73 {
74 int ret = 0;
75 if (ctx) {
76 ctx->md = *type;
77 if (ctx->md.init_fn) {
78 ret = ctx->md.init_fn(ctx);
79 if (!ret) {
80 PPP_crypto_error("Could not initialize digest");
81 }
82 }
83 }
84 return ret;
85 }
86
PPP_DigestUpdate(PPP_MD_CTX * ctx,const void * data,size_t length)87 int PPP_DigestUpdate(PPP_MD_CTX *ctx, const void *data, size_t length)
88 {
89 int ret = 0;
90 if (ctx && ctx->md.update_fn) {
91 ret = ctx->md.update_fn(ctx, data, length);
92 if (!ret) {
93 PPP_crypto_error("Could not update digest");
94 }
95 }
96 return ret;
97 }
98
PPP_DigestFinal(PPP_MD_CTX * ctx,unsigned char * out,unsigned int * outlen)99 int PPP_DigestFinal(PPP_MD_CTX *ctx, unsigned char *out, unsigned int *outlen)
100 {
101 int ret = 0;
102 if (ctx && ctx->md.final_fn) {
103 ret = ctx->md.final_fn(ctx, out, outlen);
104 if (!ret) {
105 PPP_crypto_error("Could not perform final digest");
106 }
107 }
108 return ret;
109 }
110
PPP_CIPHER_CTX_new(void)111 PPP_CIPHER_CTX *PPP_CIPHER_CTX_new(void)
112 {
113 return calloc(1, sizeof(PPP_CIPHER_CTX));
114 }
115
PPP_CIPHER_CTX_free(PPP_CIPHER_CTX * ctx)116 void PPP_CIPHER_CTX_free(PPP_CIPHER_CTX *ctx)
117 {
118 if (ctx) {
119 if (ctx->cipher.clean_fn) {
120 ctx->cipher.clean_fn(ctx);
121 }
122 memset(ctx->iv, 0, sizeof(ctx->iv));
123 memset(ctx->key, 0, sizeof(ctx->key));
124 free(ctx);
125 }
126 }
127
PPP_CipherInit(PPP_CIPHER_CTX * ctx,const PPP_CIPHER * cipher,const unsigned char * key,const unsigned char * iv,int encr)128 int PPP_CipherInit(PPP_CIPHER_CTX *ctx, const PPP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv, int encr)
129 {
130 int ret = 0;
131 if (ctx && cipher) {
132 ret = 1;
133 ctx->is_encr = encr;
134 ctx->cipher = *cipher;
135 if (ctx->cipher.init_fn) {
136 ret = ctx->cipher.init_fn(ctx, key, iv);
137 if (!ret) {
138 PPP_crypto_error("Could not initialize cipher");
139 }
140 }
141 }
142 return ret;
143 }
144
PPP_CipherUpdate(PPP_CIPHER_CTX * ctx,unsigned char * out,int * outl,const unsigned char * in,int inl)145 int PPP_CipherUpdate(PPP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl)
146 {
147 int ret = 0;
148 if (ctx && ctx->cipher.update_fn) {
149 ret = ctx->cipher.update_fn(ctx, out, outl, in, inl);
150 if (!ret) {
151 PPP_crypto_error("Could not perform crypto operation");
152 }
153 }
154 return ret;
155 }
156
PPP_CipherFinal(PPP_CIPHER_CTX * ctx,unsigned char * out,int * outl)157 int PPP_CipherFinal(PPP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
158 {
159 int ret = 0;
160 if (ctx && ctx->cipher.final_fn) {
161 ret = ctx->cipher.final_fn(ctx, out, outl);
162 if (!ret) {
163 PPP_crypto_error("Could not perform final crypto operation");
164 }
165 }
166 return ret;
167 }
168
169 void
PPP_crypto_error(char * fmt,...)170 PPP_crypto_error(char *fmt, ...)
171 {
172 va_list args;
173 char buf[1024];
174 int len = sizeof(buf);
175 int off = 0;
176 int err = 0;
177
178 va_start(args, fmt);
179 off = vsnprintf(buf, len, fmt, args);
180 va_end(args);
181
182 #ifdef PPP_WITH_OPENSSL
183 err = ERR_peek_error();
184 if (err == 0 || (len-off) < 130) {
185 error("%s", buf);
186 return;
187 }
188
189 #if OPENSSL_VERSION_NUMBER < 0x10100000L
190 ERR_load_crypto_strings();
191 #endif
192 error("%s, %s\n", buf, ERR_reason_error_string(err));
193 #else
194 error("%s", buf);
195 #endif
196 }
197
198
PPP_crypto_init()199 int PPP_crypto_init()
200 {
201 int retval = 0;
202
203 #ifdef PPP_WITH_OPENSSL
204 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
205 g_crypto_ctx.legacy = OSSL_PROVIDER_load(NULL, "legacy");
206 if (g_crypto_ctx.legacy == NULL)
207 {
208 PPP_crypto_error("Could not load legacy provider");
209 goto done;
210 }
211
212 g_crypto_ctx.provider = OSSL_PROVIDER_load(NULL, "default");
213 if (g_crypto_ctx.provider == NULL)
214 {
215 PPP_crypto_error("Could not load default provider");
216 goto done;
217 }
218 #endif
219 #endif
220
221 retval = 1;
222
223 done:
224
225 return retval;
226 }
227
PPP_crypto_deinit()228 int PPP_crypto_deinit()
229 {
230 #ifdef PPP_WITH_OPENSSL
231 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
232 if (g_crypto_ctx.legacy) {
233 OSSL_PROVIDER_unload(g_crypto_ctx.legacy);
234 g_crypto_ctx.legacy = NULL;
235 }
236
237 if (g_crypto_ctx.provider) {
238 OSSL_PROVIDER_unload(g_crypto_ctx.provider);
239 g_crypto_ctx.provider = NULL;
240 }
241 #endif
242
243 #if OPENSSL_VERSION_NUMBER < 0x10100000L
244 ERR_free_strings();
245 #endif
246 #endif
247 return 1;
248 }
249
250 #ifdef UNIT_TEST
251
252 int debug;
253 int error_count;
254 int unsuccess;
255
256
test_md4()257 int test_md4()
258 {
259 PPP_MD_CTX* ctx = NULL;
260 int success = 0;
261
262 unsigned char data[84] = {
263 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
264 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
265 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
266 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
267 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
268 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
269 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
270 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
271 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
272 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
273 0x6b, 0x65, 0x79, 0x2e
274 };
275
276 unsigned int hash_len;
277 unsigned char hash[MD4_DIGEST_LENGTH];
278 unsigned char result[MD4_DIGEST_LENGTH] = {
279 0x58, 0xcb, 0x37, 0x91, 0x1d, 0x06, 0x7b, 0xdf,
280 0xfd, 0x48, 0x6d, 0x87, 0x4a, 0x35, 0x5b, 0xd4
281 };
282
283 ctx = PPP_MD_CTX_new();
284 if (ctx) {
285
286 if (PPP_DigestInit(ctx, PPP_md4())) {
287
288 if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
289
290 hash_len = sizeof(hash);
291 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
292
293 if (memcmp(hash, result, MD4_DIGEST_LENGTH) == 0) {
294 success = 1;
295 }
296 }
297 }
298 }
299 PPP_MD_CTX_free(ctx);
300 }
301
302 return success;
303 }
304
test_md5()305 int test_md5()
306 {
307 PPP_MD_CTX* ctx = NULL;
308 int success = 0;
309
310 unsigned char data[84] = {
311 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
312 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
313 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
314 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
315 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
316 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
317 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
318 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
319 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
320 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
321 0x6b, 0x65, 0x79, 0x2e
322 };
323
324 unsigned int hash_len;
325 unsigned char hash[MD5_DIGEST_LENGTH];
326 unsigned char result[MD5_DIGEST_LENGTH] = {
327 0x8b, 0xe3, 0x5e, 0x2c, 0x9f, 0x95, 0xbf, 0x4e,
328 0x16, 0xe4, 0x53, 0xbe, 0x52, 0xf4, 0xbc, 0x4e
329 };
330
331 ctx = PPP_MD_CTX_new();
332 if (ctx) {
333
334 if (PPP_DigestInit(ctx, PPP_md5())) {
335
336 if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
337
338 hash_len = sizeof(hash);
339 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
340
341 if (memcmp(hash, result, MD5_DIGEST_LENGTH) == 0) {
342 success = 1;
343 }
344 }
345 }
346 }
347 PPP_MD_CTX_free(ctx);
348 }
349
350 return success;
351 }
352
test_sha()353 int test_sha()
354 {
355 PPP_MD_CTX* ctx = NULL;
356 int success = 0;
357
358 unsigned char data[84] = {
359 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
360 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
361 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
362 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
363 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
364 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
365 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
366 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
367 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
368 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
369 0x6b, 0x65, 0x79, 0x2e
370 };
371
372 unsigned int hash_len;
373 unsigned char hash[SHA_DIGEST_LENGTH];
374 unsigned char result[SHA_DIGEST_LENGTH] = {
375 0xa8, 0x03, 0xae, 0x21, 0x30, 0xd8, 0x40, 0xbe,
376 0x27, 0xa3, 0x47, 0xc7, 0x7a, 0x90, 0xe6, 0xa3,
377 0x5b, 0xd5, 0x0e, 0x45
378 };
379
380 ctx = PPP_MD_CTX_new();
381 if (ctx) {
382
383 if (PPP_DigestInit(ctx, PPP_sha1())) {
384
385 if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
386
387 hash_len = sizeof(hash);
388 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
389
390 if (memcmp(hash, result, SHA_DIGEST_LENGTH) == 0) {
391 success = 1;
392 }
393 }
394 }
395 }
396 PPP_MD_CTX_free(ctx);
397 }
398
399 return success;
400 }
401
test_des_encrypt()402 int test_des_encrypt()
403 {
404 PPP_CIPHER_CTX* ctx = NULL;
405 int success = 0;
406
407 unsigned char key[8] = {
408 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
409 };
410
411 unsigned char plain[80] = {
412 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
413 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
414 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
415 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
416 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
417 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
418 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
419 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
420 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
421 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20
422 };
423 unsigned char expect[80] = {
424 0x45, 0xdb, 0x80, 0x45, 0x16, 0xd0, 0x6d, 0x60,
425 0x92, 0x23, 0x4b, 0xd3, 0x9d, 0x36, 0xb8, 0x1a,
426 0xa4, 0x1a, 0xf7, 0xb1, 0x60, 0xfb, 0x74, 0x16,
427 0xa6, 0xdc, 0xe1, 0x14, 0xb7, 0xed, 0x48, 0x5a,
428 0x2b, 0xed, 0x68, 0x9d, 0x19, 0xd6, 0xb1, 0xb8,
429 0x91, 0xff, 0xea, 0x62, 0xac, 0xe7, 0x49, 0xdd,
430 0xfa, 0x4d, 0xa4, 0x01, 0x3f, 0xea, 0xca, 0xb4,
431 0xb6, 0xdc, 0xd3, 0x04, 0x45, 0x07, 0x74, 0xed,
432 0xa6, 0xdc, 0xe1, 0x14, 0xb7, 0xed, 0x48, 0x5a,
433 0xbb, 0x9b, 0x13, 0x31, 0xf4, 0xa9, 0x32, 0x49
434 };
435
436 unsigned char cipher[80] = {};
437 int cipher_len = 0;
438 int offset = 0;
439
440
441 ctx = PPP_CIPHER_CTX_new();
442 if (ctx) {
443
444 if (PPP_CipherInit(ctx, PPP_des_ecb(), key, NULL, 1)) {
445
446 if (PPP_CipherUpdate(ctx, cipher, &cipher_len, plain, sizeof(plain))) {
447
448 offset += cipher_len;
449
450 if (PPP_CipherFinal(ctx, cipher+offset, &cipher_len)) {
451
452 if (memcmp(cipher, expect, 80) == 0) {
453
454 success = 1;
455 }
456 }
457 }
458 }
459 PPP_CIPHER_CTX_free(ctx);
460 }
461
462 return success;
463 }
464
465
test_des_decrypt()466 int test_des_decrypt()
467 {
468 PPP_CIPHER_CTX* ctx = NULL;
469 int success = 0;
470
471 unsigned char key[8] = {
472 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
473 };
474
475 unsigned char cipher[80] = {
476 0x45, 0xdb, 0x80, 0x45, 0x16, 0xd0, 0x6d, 0x60,
477 0x92, 0x23, 0x4b, 0xd3, 0x9d, 0x36, 0xb8, 0x1a,
478 0xa4, 0x1a, 0xf7, 0xb1, 0x60, 0xfb, 0x74, 0x16,
479 0xa6, 0xdc, 0xe1, 0x14, 0xb7, 0xed, 0x48, 0x5a,
480 0x2b, 0xed, 0x68, 0x9d, 0x19, 0xd6, 0xb1, 0xb8,
481 0x91, 0xff, 0xea, 0x62, 0xac, 0xe7, 0x49, 0xdd,
482 0xfa, 0x4d, 0xa4, 0x01, 0x3f, 0xea, 0xca, 0xb4,
483 0xb6, 0xdc, 0xd3, 0x04, 0x45, 0x07, 0x74, 0xed,
484 0xa6, 0xdc, 0xe1, 0x14, 0xb7, 0xed, 0x48, 0x5a,
485 0xbb, 0x9b, 0x13, 0x31, 0xf4, 0xa9, 0x32, 0x49
486 };
487
488 unsigned char expect[80] = {
489 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
490 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
491 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
492 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
493 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
494 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
495 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
496 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
497 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
498 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20
499 };
500
501 unsigned char plain[80] = {};
502 int outlen = 0;
503 int offset = 0;
504
505 ctx = PPP_CIPHER_CTX_new();
506 if (ctx) {
507
508 if (PPP_CipherInit(ctx, PPP_des_ecb(), key, NULL, 0)) {
509
510 if (PPP_CipherUpdate(ctx, plain, &outlen, cipher, sizeof(cipher))) {
511
512 offset += outlen;
513
514 if (PPP_CipherFinal(ctx, plain+offset, &outlen)) {
515
516 if (memcmp(plain, expect, 80) == 0) {
517
518 success = 1;
519 }
520 }
521 }
522 }
523 PPP_CIPHER_CTX_free(ctx);
524 }
525
526 return success;
527 }
528
main(int argc,char * argv[])529 int main(int argc, char *argv[])
530 {
531 int failure = 0;
532
533 if (!PPP_crypto_init()) {
534 printf("Couldn't initialize crypto test\n");
535 return -1;
536 }
537
538 if (!test_md4()) {
539 printf("MD4 test failed\n");
540 failure++;
541 }
542
543 if (!test_md5()) {
544 printf("MD5 test failed\n");
545 failure++;
546 }
547
548 if (!test_sha()) {
549 printf("SHA test failed\n");
550 failure++;
551 }
552
553 if (!test_des_encrypt()) {
554 printf("DES encryption test failed\n");
555 failure++;
556 }
557
558 if (!test_des_decrypt()) {
559 printf("DES decryption test failed\n");
560 failure++;
561 }
562
563 if (!PPP_crypto_deinit()) {
564 printf("Couldn't deinitialize crypto test\n");
565 return -1;
566 }
567
568 return failure;
569 }
570
571 #endif
572