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