1 /* ppp-crypto.c - Generic API for access to crypto/digest functions. 2 * 3 * Copyright (c) 2022 Eivind Nss. 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 57 PPP_MD_CTX *PPP_MD_CTX_new() 58 { 59 return (PPP_MD_CTX*) calloc(1, sizeof(PPP_MD_CTX)); 60 } 61 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 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 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 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 111 PPP_CIPHER_CTX *PPP_CIPHER_CTX_new(void) 112 { 113 return calloc(1, sizeof(PPP_CIPHER_CTX)); 114 } 115 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 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 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 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 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 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 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 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 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 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 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 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 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