]> git.ozlabs.org Git - ppp.git/blob - pppd/ppp-crypto.c
Create a new API to abstract the crypto functions used by pppd.
[ppp.git] / pppd / ppp-crypto.c
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
38 #include "ppp-crypto.h"
39 #include "ppp-crypto-priv.h"
40
41 #ifdef PPP_WITH_OPENSSL
42 #include <openssl/opensslv.h>
43 #endif
44
45 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
46 #include <openssl/provider.h>
47 struct crypto_ctx {
48
49     OSSL_PROVIDER *legacy;
50     OSSL_PROVIDER *provider;
51 } g_crypto_ctx;
52 #endif
53
54 PPP_MD_CTX *PPP_MD_CTX_new()
55 {
56     return (PPP_MD_CTX*) calloc(1, sizeof(PPP_MD_CTX));
57 }
58
59 void PPP_MD_CTX_free(PPP_MD_CTX* ctx)
60 {
61     if (ctx) {
62         if (ctx->md.clean_fn) {
63             ctx->md.clean_fn(ctx);
64         }
65         free(ctx);
66     }
67 }
68
69 int PPP_DigestInit(PPP_MD_CTX *ctx, const PPP_MD *type)
70 {
71     if (ctx) {
72         ctx->md = *type;
73         if (ctx->md.init_fn) {
74             return ctx->md.init_fn(ctx);
75         }
76     }
77     return 0;
78 }
79
80 int PPP_DigestUpdate(PPP_MD_CTX *ctx, const void *data, size_t length)
81 {
82     if (ctx && ctx->md.update_fn) {
83         return ctx->md.update_fn(ctx, data, length);
84     }
85     return 0;
86 }
87
88 int PPP_DigestFinal(PPP_MD_CTX *ctx, unsigned char *out, unsigned int *outlen)
89 {
90     if (ctx && ctx->md.final_fn) {
91         return ctx->md.final_fn(ctx, out, outlen);
92     }
93     return 0;
94 }
95
96 PPP_CIPHER_CTX *PPP_CIPHER_CTX_new(void)
97 {
98     return calloc(1, sizeof(PPP_CIPHER_CTX));
99 }
100
101 void PPP_CIPHER_CTX_free(PPP_CIPHER_CTX *ctx)
102 {
103     if (ctx) {
104         if (ctx->cipher.clean_fn) {
105             ctx->cipher.clean_fn(ctx);
106         }
107         memset(ctx->iv, 0, sizeof(ctx->iv));
108         memset(ctx->key, 0, sizeof(ctx->key));
109         free(ctx);
110     }
111 }
112
113 int PPP_CipherInit(PPP_CIPHER_CTX *ctx, const PPP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv, int encr)
114 {
115     if (ctx && cipher) {
116         ctx->is_encr = encr;
117         ctx->cipher = *cipher;
118         if (ctx->cipher.init_fn) {
119             ctx->cipher.init_fn(ctx, key, iv);
120         }
121         return 1;
122     }
123     return 0;
124 }
125
126 int PPP_CipherUpdate(PPP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl)
127 {
128     if (ctx && ctx->cipher.update_fn) {
129         return ctx->cipher.update_fn(ctx, out, outl, in, inl);
130     }
131     return 0;
132 }
133
134 int PPP_CipherFinal(PPP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
135 {
136     if (ctx && ctx->cipher.final_fn) {
137         return ctx->cipher.final_fn(ctx, out, outl);
138     }
139     return 0;
140 }
141
142 void PPP_CIPHER_CTX_set_cipher_data(PPP_CIPHER_CTX *ctx, const unsigned char *key)
143 {
144     if (ctx && ctx->cipher.set_key_fn) {
145         ctx->cipher.set_key_fn(ctx, key);
146     }
147 }
148
149
150 int PPP_crypto_init()
151 {
152     int retval = 0;
153
154 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
155     g_crypto_ctx.legacy = OSSL_PROVIDER_load(NULL, "legacy");
156     if (g_crypto_ctx.legacy == NULL)
157     {
158         goto done;
159     }
160
161     g_crypto_ctx.provider = OSSL_PROVIDER_load(NULL, "default");
162     if (g_crypto_ctx.provider == NULL)
163     {
164         goto done;
165     }
166 #endif
167     retval = 1;
168
169 done:
170
171     return retval;
172 }
173
174 int PPP_crypto_deinit()
175 {
176 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
177     if (g_crypto_ctx.legacy) {
178         OSSL_PROVIDER_unload(g_crypto_ctx.legacy);
179         g_crypto_ctx.legacy = NULL;
180     }
181
182     if (g_crypto_ctx.provider) {
183         OSSL_PROVIDER_unload(g_crypto_ctx.provider);
184         g_crypto_ctx.provider = NULL;
185     }
186 #endif
187     return 1;
188 }
189
190 #ifdef UNIT_TEST
191 #include <stdio.h>
192
193 int test_md4()
194 {
195     PPP_MD_CTX* ctx = NULL;
196     int success = 0;
197
198     unsigned char data[84] = {
199         0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
200         0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
201         0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
202         0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
203         0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
204         0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
205         0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
206         0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
207         0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
208         0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
209             0x6b, 0x65, 0x79, 0x2e
210     };
211
212     unsigned int  hash_len;
213     unsigned char hash[MD4_DIGEST_LENGTH];
214     unsigned char result[MD4_DIGEST_LENGTH] = {
215         0x58, 0xcb, 0x37, 0x91, 0x1d, 0x06, 0x7b, 0xdf,
216         0xfd, 0x48, 0x6d, 0x87, 0x4a, 0x35, 0x5b, 0xd4
217     };
218
219     ctx = PPP_MD_CTX_new();
220     if (ctx) {
221
222         if (PPP_DigestInit(ctx, PPP_md4())) {
223
224             if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
225
226                 hash_len = sizeof(hash);
227                 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
228
229                     if (memcmp(hash, result, MD4_DIGEST_LENGTH) == 0) {
230                         success = 1;
231                     }
232                 }
233             }
234         }
235         PPP_MD_CTX_free(ctx);
236     }
237
238     return success;
239 }
240
241 int test_md5()
242 {
243     PPP_MD_CTX* ctx = NULL;
244     int success = 0;
245
246     unsigned char data[84] = {
247         0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
248         0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
249         0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
250         0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
251         0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
252         0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
253         0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
254         0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
255         0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
256         0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
257             0x6b, 0x65, 0x79, 0x2e
258     };
259
260     unsigned int  hash_len;
261     unsigned char hash[MD5_DIGEST_LENGTH];
262     unsigned char result[MD5_DIGEST_LENGTH] = {
263         0x8b, 0xe3, 0x5e, 0x2c, 0x9f, 0x95, 0xbf, 0x4e,
264         0x16, 0xe4, 0x53, 0xbe, 0x52, 0xf4, 0xbc, 0x4e
265     };
266
267     ctx = PPP_MD_CTX_new();
268     if (ctx) {
269
270         if (PPP_DigestInit(ctx, PPP_md5())) {
271
272             if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
273
274                 hash_len = sizeof(hash);
275                 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
276
277                     if (memcmp(hash, result, MD5_DIGEST_LENGTH) == 0) {
278                         success = 1;
279                     }
280                 }
281             }
282         }
283         PPP_MD_CTX_free(ctx);
284     }
285
286     return success;
287 }
288
289 int test_sha()
290 {
291     PPP_MD_CTX* ctx = NULL;
292     int success = 0;
293
294     unsigned char data[84] = {
295         0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
296         0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
297         0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
298         0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
299         0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
300         0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
301         0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
302         0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
303         0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
304         0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
305             0x6b, 0x65, 0x79, 0x2e
306     };
307
308     unsigned int  hash_len;
309     unsigned char hash[SHA_DIGEST_LENGTH];
310     unsigned char result[SHA_DIGEST_LENGTH] = {
311         0xa8, 0x03, 0xae, 0x21, 0x30, 0xd8, 0x40, 0xbe,
312         0x27, 0xa3, 0x47, 0xc7, 0x7a, 0x90, 0xe6, 0xa3,
313         0x5b, 0xd5, 0x0e, 0x45
314     };
315
316     ctx = PPP_MD_CTX_new();
317     if (ctx) {
318
319         if (PPP_DigestInit(ctx, PPP_sha1())) {
320
321             if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
322
323                 hash_len = sizeof(hash);
324                 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
325
326                     if (memcmp(hash, result, SHA_DIGEST_LENGTH) == 0) {
327                         success = 1;
328                     }
329                 }
330             }
331         }
332         PPP_MD_CTX_free(ctx);
333     }
334
335     return success;
336 }
337
338 int test_des_encrypt()
339 {
340     PPP_CIPHER_CTX* ctx = NULL;
341     int success = 0;
342
343     unsigned char key[8] = {
344         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
345     };
346
347     unsigned char plain[80] = {
348         0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
349         0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
350         0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
351         0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
352         0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
353         0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
354         0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
355         0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
356         0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
357         0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20
358     };
359     unsigned char expect[80] = {
360         0x5d, 0xa7, 0x47, 0xc5, 0x1a, 0xb1, 0x71, 0xff,
361         0xc8, 0x45, 0x7c, 0xa7, 0x07, 0xec, 0x4b, 0x13,
362         0x47, 0x55, 0x77, 0xbc, 0xcf, 0x71, 0xd9, 0x27,
363         0x23, 0x12, 0x2a, 0x17, 0x20, 0xad, 0xc1, 0x19,
364         0x3e, 0x74, 0x38, 0x29, 0x48, 0xb0, 0xd2, 0xe2,
365         0x18, 0x45, 0xdd, 0x8a, 0x9b, 0x8d, 0x40, 0xec,
366         0x9e, 0x0c, 0x41, 0xa3, 0x36, 0x40, 0xf5, 0x91,
367         0x41, 0x44, 0xde, 0xa1, 0xb5, 0x9d, 0x39, 0x99,
368         0x23, 0x12, 0x2a, 0x17, 0x20, 0xad, 0xc1, 0x19,
369         0xee, 0xe3, 0xbe, 0x0b, 0x83, 0x36, 0xe1, 0x25
370     };
371
372     unsigned char cipher[80] = {};
373     int cipher_len = 0;
374     int offset = 0;
375
376
377     ctx = PPP_CIPHER_CTX_new();
378     if (ctx) {
379
380         if (PPP_CipherInit(ctx, PPP_des_ecb(), key, NULL, 1)) {
381
382             if (PPP_CipherUpdate(ctx, cipher, &cipher_len, plain, sizeof(plain))) {
383
384                 offset += cipher_len;
385
386                 if (PPP_CipherFinal(ctx, cipher+offset, &cipher_len)) {
387
388                     if (memcmp(cipher, expect, 80) == 0) {
389
390                         success = 1;
391                     }
392                 }
393             }
394         }
395         PPP_CIPHER_CTX_free(ctx);
396     }
397
398     return success;
399 }
400
401
402 int test_des_decrypt()
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 cipher[80] = {
412         0x5d, 0xa7, 0x47, 0xc5, 0x1a, 0xb1, 0x71, 0xff,
413         0xc8, 0x45, 0x7c, 0xa7, 0x07, 0xec, 0x4b, 0x13,
414         0x47, 0x55, 0x77, 0xbc, 0xcf, 0x71, 0xd9, 0x27,
415         0x23, 0x12, 0x2a, 0x17, 0x20, 0xad, 0xc1, 0x19,
416         0x3e, 0x74, 0x38, 0x29, 0x48, 0xb0, 0xd2, 0xe2,
417         0x18, 0x45, 0xdd, 0x8a, 0x9b, 0x8d, 0x40, 0xec,
418         0x9e, 0x0c, 0x41, 0xa3, 0x36, 0x40, 0xf5, 0x91,
419         0x41, 0x44, 0xde, 0xa1, 0xb5, 0x9d, 0x39, 0x99,
420         0x23, 0x12, 0x2a, 0x17, 0x20, 0xad, 0xc1, 0x19,
421         0xee, 0xe3, 0xbe, 0x0b, 0x83, 0x36, 0xe1, 0x25
422     };
423
424     unsigned char expect[80] = {
425         0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
426         0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
427         0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
428         0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
429         0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
430         0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
431         0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
432         0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
433         0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
434         0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20
435     };
436
437     unsigned char plain[80] = {};
438     int outlen = 0;
439     int offset = 0;
440
441     ctx = PPP_CIPHER_CTX_new();
442     if (ctx) {
443
444         if (PPP_CipherInit(ctx, PPP_des_ecb(), key, NULL, 0)) {
445
446             if (PPP_CipherUpdate(ctx, plain, &outlen, cipher, sizeof(cipher))) {
447
448                 offset += outlen;
449
450                 if (PPP_CipherFinal(ctx, plain+offset, &outlen)) {
451
452                     if (memcmp(plain, 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 int main(int argc, char *argv[]) {
466     int failure = 0;
467
468     if (!PPP_crypto_init()) {
469         printf("Couldn't initialize crypto test\n");
470         return -1;
471     }
472
473     if (!test_md4()) {
474         printf("MD4 test failed\n");
475         failure++;
476     }
477
478     if (!test_md5()) {
479         printf("MD5 test failed\n");
480         failure++;
481     }
482
483     if (!test_sha()) {
484         printf("SHA test failed\n");
485         failure++;
486     }
487
488     if (!test_des_encrypt()) {
489         printf("DES encryption test failed\n");
490         failure++;
491     }
492
493     /* Bug in DES EVP decryption, TODO: file an issue
494     if (!test_des_decrypt()) {
495         printf("DES decryption test failed\n");
496         failure++;
497     }
498     */
499
500     if (!PPP_crypto_deinit()) {
501         printf("Couldn't deinitialize crypto test\n");
502         return -1;
503     }
504
505     return failure;
506 }
507
508 #endif