Home | History | Annotate | Line # | Download | only in pppd
      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