summaryrefslogtreecommitdiff
path: root/pppd/crypto.c
diff options
context:
space:
mode:
authorEivind Næss <eivnaes@yahoo.com>2023-01-20 22:12:58 -0800
committerGitHub <noreply@github.com>2023-01-21 17:12:58 +1100
commitba7f7e053daae846a54a1d08d3d133a5f1266ace (patch)
tree3da27cf3ca6d6eb76e3f9a05db4c5676591d5002 /pppd/crypto.c
parent76016e1b948b7d9675b4e0750d1f943d96d9523b (diff)
downloadppp-ba7f7e053daae846a54a1d08d3d133a5f1266ace.tar.gz
Header file reorganization and cleaning up the public API for pppd version 2.5.0 (#379)
This commit does several things, being a squash-and-merge of a series of changes; squashed in order not to break bisection. * Clean up pppd.h, moving declarations that should only be accessed by pppd code (not by users of pppd) to a new pppd-private.h. Also, other parts of pppd.h were moved to multilink.h, chap.h, eap.h, eui64.h, and a new options.h. * Provide an API for access to data that is needed by plugins (in no particular order): - ifname - ifunit - remote_name - remote_number - peer_authname - status (now called "code" internally) - phase - doing_multilink - multilink_master - idle_time_limit - link_connect_time - max_connect_time - link_stats - ipparam - hostname - got_sigterm - got_sigusr2 - got_sighup - session_number - maxoctets - maxoctets_dir - debug - persist - devnam - modem - peer_authname - sync_serial * Update the version number to 2.5.0. * Detect availability of stddef.h and stdarg.h. * Rename some headers: - pppcrypt.c/h to crypto_ms.c/h - ppp-crypto.c/h to crypto.c/h - ppp-crypto-priv.h to crypto-priv.h - chap-new.c/h to chap.c/h * Remove chap-md5.h, crypto-priv.h, eap-tls.h, etc. from the list of header files to be installed. * Provide typedefs for the hook functions. * Provide a typedef for the "phase" variable. * Provide a typedef for the link statistics array. * Remove the option_t typedef. * Rename the following functions by adding a "ppp_" prefix (with the intention that these are a "public" API for use by plugins): - option_error - add_options - int_option, - options_from_file - script_setenv - bad_ip_adrs, - netif_get/set_mtu (renamed to ppp_get/set_mtu) - get_time - timeout - untimeout - safe_fork - sys_close - set_session_number - update_link_stats (renamed to ppp_get_link_stats) - add_notifier (renamed to ppp_add_notify) - remove_notifier (renamed to ppp_del_notify) - generic_[dis]establish_ppp (to ppp_generic_[dis]establish) * Rename ppp_devnam to ppp_devname. * Rename ppp_available() to ppp_check_kernel_support(). * Use unsigned char instead of u_char, unsigned short instead of u_short, uint32_t instead of u_int32_t. * Add const to some declarations * Update comments * Change the interface for notifiers to use an enum to identify which notifier is to be modified. * Provide an API for getting the path to a file, with an enum to identify different types of file. * Link plugins with the -DPLUGIN flag [paulus@ozlabs.org - wrote commit message] Signed-off-by: Eivind Næss <eivnaes@yahoo.com> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Diffstat (limited to 'pppd/crypto.c')
-rw-r--r--pppd/crypto.c499
1 files changed, 499 insertions, 0 deletions
diff --git a/pppd/crypto.c b/pppd/crypto.c
new file mode 100644
index 0000000..905f11d
--- /dev/null
+++ b/pppd/crypto.c
@@ -0,0 +1,499 @@
+/* ppp-crypto.c - Generic API for access to crypto/digest functions.
+ *
+ * Copyright (c) 2022 Eivind Næss. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name(s) of the authors of this software must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "crypto.h"
+#include "crypto-priv.h"
+
+#ifdef PPP_WITH_OPENSSL
+#include <openssl/opensslv.h>
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/provider.h>
+struct crypto_ctx {
+
+ OSSL_PROVIDER *legacy;
+ OSSL_PROVIDER *provider;
+} g_crypto_ctx;
+#endif
+
+PPP_MD_CTX *PPP_MD_CTX_new()
+{
+ return (PPP_MD_CTX*) calloc(1, sizeof(PPP_MD_CTX));
+}
+
+void PPP_MD_CTX_free(PPP_MD_CTX* ctx)
+{
+ if (ctx) {
+ if (ctx->md.clean_fn) {
+ ctx->md.clean_fn(ctx);
+ }
+ free(ctx);
+ }
+}
+
+int PPP_DigestInit(PPP_MD_CTX *ctx, const PPP_MD *type)
+{
+ if (ctx) {
+ ctx->md = *type;
+ if (ctx->md.init_fn) {
+ return ctx->md.init_fn(ctx);
+ }
+ }
+ return 0;
+}
+
+int PPP_DigestUpdate(PPP_MD_CTX *ctx, const void *data, size_t length)
+{
+ if (ctx && ctx->md.update_fn) {
+ return ctx->md.update_fn(ctx, data, length);
+ }
+ return 0;
+}
+
+int PPP_DigestFinal(PPP_MD_CTX *ctx, unsigned char *out, unsigned int *outlen)
+{
+ if (ctx && ctx->md.final_fn) {
+ return ctx->md.final_fn(ctx, out, outlen);
+ }
+ return 0;
+}
+
+PPP_CIPHER_CTX *PPP_CIPHER_CTX_new(void)
+{
+ return calloc(1, sizeof(PPP_CIPHER_CTX));
+}
+
+void PPP_CIPHER_CTX_free(PPP_CIPHER_CTX *ctx)
+{
+ if (ctx) {
+ if (ctx->cipher.clean_fn) {
+ ctx->cipher.clean_fn(ctx);
+ }
+ memset(ctx->iv, 0, sizeof(ctx->iv));
+ memset(ctx->key, 0, sizeof(ctx->key));
+ free(ctx);
+ }
+}
+
+int PPP_CipherInit(PPP_CIPHER_CTX *ctx, const PPP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv, int encr)
+{
+ if (ctx && cipher) {
+ ctx->is_encr = encr;
+ ctx->cipher = *cipher;
+ if (ctx->cipher.init_fn) {
+ ctx->cipher.init_fn(ctx, key, iv);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int PPP_CipherUpdate(PPP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl)
+{
+ if (ctx && ctx->cipher.update_fn) {
+ return ctx->cipher.update_fn(ctx, out, outl, in, inl);
+ }
+ return 0;
+}
+
+int PPP_CipherFinal(PPP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
+{
+ if (ctx && ctx->cipher.final_fn) {
+ return ctx->cipher.final_fn(ctx, out, outl);
+ }
+ return 0;
+}
+
+int PPP_crypto_init()
+{
+ int retval = 0;
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ g_crypto_ctx.legacy = OSSL_PROVIDER_load(NULL, "legacy");
+ if (g_crypto_ctx.legacy == NULL)
+ {
+ goto done;
+ }
+
+ g_crypto_ctx.provider = OSSL_PROVIDER_load(NULL, "default");
+ if (g_crypto_ctx.provider == NULL)
+ {
+ goto done;
+ }
+#endif
+ retval = 1;
+
+done:
+
+ return retval;
+}
+
+int PPP_crypto_deinit()
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (g_crypto_ctx.legacy) {
+ OSSL_PROVIDER_unload(g_crypto_ctx.legacy);
+ g_crypto_ctx.legacy = NULL;
+ }
+
+ if (g_crypto_ctx.provider) {
+ OSSL_PROVIDER_unload(g_crypto_ctx.provider);
+ g_crypto_ctx.provider = NULL;
+ }
+#endif
+ return 1;
+}
+
+#ifdef UNIT_TEST
+#include <stdio.h>
+
+int test_md4()
+{
+ PPP_MD_CTX* ctx = NULL;
+ int success = 0;
+
+ unsigned char data[84] = {
+ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
+ 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
+ 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
+ 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+ 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
+ 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
+ 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+ 0x6b, 0x65, 0x79, 0x2e
+ };
+
+ unsigned int hash_len;
+ unsigned char hash[MD4_DIGEST_LENGTH];
+ unsigned char result[MD4_DIGEST_LENGTH] = {
+ 0x58, 0xcb, 0x37, 0x91, 0x1d, 0x06, 0x7b, 0xdf,
+ 0xfd, 0x48, 0x6d, 0x87, 0x4a, 0x35, 0x5b, 0xd4
+ };
+
+ ctx = PPP_MD_CTX_new();
+ if (ctx) {
+
+ if (PPP_DigestInit(ctx, PPP_md4())) {
+
+ if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
+
+ hash_len = sizeof(hash);
+ if (PPP_DigestFinal(ctx, hash, &hash_len)) {
+
+ if (memcmp(hash, result, MD4_DIGEST_LENGTH) == 0) {
+ success = 1;
+ }
+ }
+ }
+ }
+ PPP_MD_CTX_free(ctx);
+ }
+
+ return success;
+}
+
+int test_md5()
+{
+ PPP_MD_CTX* ctx = NULL;
+ int success = 0;
+
+ unsigned char data[84] = {
+ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
+ 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
+ 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
+ 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+ 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
+ 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
+ 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+ 0x6b, 0x65, 0x79, 0x2e
+ };
+
+ unsigned int hash_len;
+ unsigned char hash[MD5_DIGEST_LENGTH];
+ unsigned char result[MD5_DIGEST_LENGTH] = {
+ 0x8b, 0xe3, 0x5e, 0x2c, 0x9f, 0x95, 0xbf, 0x4e,
+ 0x16, 0xe4, 0x53, 0xbe, 0x52, 0xf4, 0xbc, 0x4e
+ };
+
+ ctx = PPP_MD_CTX_new();
+ if (ctx) {
+
+ if (PPP_DigestInit(ctx, PPP_md5())) {
+
+ if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
+
+ hash_len = sizeof(hash);
+ if (PPP_DigestFinal(ctx, hash, &hash_len)) {
+
+ if (memcmp(hash, result, MD5_DIGEST_LENGTH) == 0) {
+ success = 1;
+ }
+ }
+ }
+ }
+ PPP_MD_CTX_free(ctx);
+ }
+
+ return success;
+}
+
+int test_sha()
+{
+ PPP_MD_CTX* ctx = NULL;
+ int success = 0;
+
+ unsigned char data[84] = {
+ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
+ 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
+ 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
+ 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+ 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
+ 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
+ 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+ 0x6b, 0x65, 0x79, 0x2e
+ };
+
+ unsigned int hash_len;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+ unsigned char result[SHA_DIGEST_LENGTH] = {
+ 0xa8, 0x03, 0xae, 0x21, 0x30, 0xd8, 0x40, 0xbe,
+ 0x27, 0xa3, 0x47, 0xc7, 0x7a, 0x90, 0xe6, 0xa3,
+ 0x5b, 0xd5, 0x0e, 0x45
+ };
+
+ ctx = PPP_MD_CTX_new();
+ if (ctx) {
+
+ if (PPP_DigestInit(ctx, PPP_sha1())) {
+
+ if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
+
+ hash_len = sizeof(hash);
+ if (PPP_DigestFinal(ctx, hash, &hash_len)) {
+
+ if (memcmp(hash, result, SHA_DIGEST_LENGTH) == 0) {
+ success = 1;
+ }
+ }
+ }
+ }
+ PPP_MD_CTX_free(ctx);
+ }
+
+ return success;
+}
+
+int test_des_encrypt()
+{
+ PPP_CIPHER_CTX* ctx = NULL;
+ int success = 0;
+
+ unsigned char key[8] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+ };
+
+ unsigned char plain[80] = {
+ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
+ 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
+ 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
+ 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+ 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
+ 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
+ 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20
+ };
+ unsigned char expect[80] = {
+ 0x45, 0xdb, 0x80, 0x45, 0x16, 0xd0, 0x6d, 0x60,
+ 0x92, 0x23, 0x4b, 0xd3, 0x9d, 0x36, 0xb8, 0x1a,
+ 0xa4, 0x1a, 0xf7, 0xb1, 0x60, 0xfb, 0x74, 0x16,
+ 0xa6, 0xdc, 0xe1, 0x14, 0xb7, 0xed, 0x48, 0x5a,
+ 0x2b, 0xed, 0x68, 0x9d, 0x19, 0xd6, 0xb1, 0xb8,
+ 0x91, 0xff, 0xea, 0x62, 0xac, 0xe7, 0x49, 0xdd,
+ 0xfa, 0x4d, 0xa4, 0x01, 0x3f, 0xea, 0xca, 0xb4,
+ 0xb6, 0xdc, 0xd3, 0x04, 0x45, 0x07, 0x74, 0xed,
+ 0xa6, 0xdc, 0xe1, 0x14, 0xb7, 0xed, 0x48, 0x5a,
+ 0xbb, 0x9b, 0x13, 0x31, 0xf4, 0xa9, 0x32, 0x49
+ };
+
+ unsigned char cipher[80] = {};
+ int cipher_len = 0;
+ int offset = 0;
+
+
+ ctx = PPP_CIPHER_CTX_new();
+ if (ctx) {
+
+ if (PPP_CipherInit(ctx, PPP_des_ecb(), key, NULL, 1)) {
+
+ if (PPP_CipherUpdate(ctx, cipher, &cipher_len, plain, sizeof(plain))) {
+
+ offset += cipher_len;
+
+ if (PPP_CipherFinal(ctx, cipher+offset, &cipher_len)) {
+
+ if (memcmp(cipher, expect, 80) == 0) {
+
+ success = 1;
+ }
+ }
+ }
+ }
+ PPP_CIPHER_CTX_free(ctx);
+ }
+
+ return success;
+}
+
+
+int test_des_decrypt()
+{
+ PPP_CIPHER_CTX* ctx = NULL;
+ int success = 0;
+
+ unsigned char key[8] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+ };
+
+ unsigned char cipher[80] = {
+ 0x45, 0xdb, 0x80, 0x45, 0x16, 0xd0, 0x6d, 0x60,
+ 0x92, 0x23, 0x4b, 0xd3, 0x9d, 0x36, 0xb8, 0x1a,
+ 0xa4, 0x1a, 0xf7, 0xb1, 0x60, 0xfb, 0x74, 0x16,
+ 0xa6, 0xdc, 0xe1, 0x14, 0xb7, 0xed, 0x48, 0x5a,
+ 0x2b, 0xed, 0x68, 0x9d, 0x19, 0xd6, 0xb1, 0xb8,
+ 0x91, 0xff, 0xea, 0x62, 0xac, 0xe7, 0x49, 0xdd,
+ 0xfa, 0x4d, 0xa4, 0x01, 0x3f, 0xea, 0xca, 0xb4,
+ 0xb6, 0xdc, 0xd3, 0x04, 0x45, 0x07, 0x74, 0xed,
+ 0xa6, 0xdc, 0xe1, 0x14, 0xb7, 0xed, 0x48, 0x5a,
+ 0xbb, 0x9b, 0x13, 0x31, 0xf4, 0xa9, 0x32, 0x49
+ };
+
+ unsigned char expect[80] = {
+ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
+ 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
+ 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
+ 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+ 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
+ 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
+ 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20
+ };
+
+ unsigned char plain[80] = {};
+ int outlen = 0;
+ int offset = 0;
+
+ ctx = PPP_CIPHER_CTX_new();
+ if (ctx) {
+
+ if (PPP_CipherInit(ctx, PPP_des_ecb(), key, NULL, 0)) {
+
+ if (PPP_CipherUpdate(ctx, plain, &outlen, cipher, sizeof(cipher))) {
+
+ offset += outlen;
+
+ if (PPP_CipherFinal(ctx, plain+offset, &outlen)) {
+
+ if (memcmp(plain, expect, 80) == 0) {
+
+ success = 1;
+ }
+ }
+ }
+ }
+ PPP_CIPHER_CTX_free(ctx);
+ }
+
+ return success;
+}
+
+int main(int argc, char *argv[])
+{
+ int failure = 0;
+
+ if (!PPP_crypto_init()) {
+ printf("Couldn't initialize crypto test\n");
+ return -1;
+ }
+
+ if (!test_md4()) {
+ printf("MD4 test failed\n");
+ failure++;
+ }
+
+ if (!test_md5()) {
+ printf("MD5 test failed\n");
+ failure++;
+ }
+
+ if (!test_sha()) {
+ printf("SHA test failed\n");
+ failure++;
+ }
+
+ if (!test_des_encrypt()) {
+ printf("DES encryption test failed\n");
+ failure++;
+ }
+
+ if (!test_des_decrypt()) {
+ printf("DES decryption test failed\n");
+ failure++;
+ }
+
+ if (!PPP_crypto_deinit()) {
+ printf("Couldn't deinitialize crypto test\n");
+ return -1;
+ }
+
+ return failure;
+}
+
+#endif