Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  mysql_sha2.c   Sprache: C

 

/*
  Copyright (c) 2025, MariaDB plc

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA */


#if _WIN32
#include <io.h>
#define access _access
#define F_OK 0
#else
#include <unistd.h>
#endif
#include "mysql_sha2.h"
#include <mysql/plugin_auth.h>
#include <mysqld_error.h>

char *private_key_path, *public_key_path, public_key[1024]={0};
size_t public_key_len=0;
EVP_PKEY *private_key= 0;

static my_bool auto_generate_keys;
static unsigned int digest_rounds;

struct digest {
  unsigned int iterations;
  unsigned char salt[SCRAMBLE_LENGTH];
  unsigned char crypted[SHA256CRYPT_LEN];
};

#define PASSWORD_LEN (SCRAMBLE_LENGTH + SHA256CRYPT_LEN + sizeof("$A$005$")-1)

#define ITERATION_MULTIPLIER 1000

static unsigned char request_public_key = '\2';
static unsigned char perform_full_authentication = '\4';

static void make_salt(unsigned char *to)
{
  unsigned char *end= to + SCRAMBLE_LENGTH;
  my_random_bytes(to, SCRAMBLE_LENGTH);
  for (; to < end; to++)
    *to = (*to % 90) + '$' + 1;
  /* in MySQL: if (*to == '\0' || *to == '$') (*to)++; */
}

static int auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
{
  struct digest *authstr;
  unsigned char to[SHA256CRYPT_LEN];
  unsigned char scramble[SCRAMBLE_LENGTH + 1], *pkt;
  int pkt_len;
  MYSQL_PLUGIN_VIO_INFO vio_info;
  unsigned char plain_text[1025];
  size_t plain_text_len= sizeof(plain_text)-1;

  make_salt(scramble);
  scramble[SCRAMBLE_LENGTH]= 0;
  if (vio->write_packet(vio, scramble, sizeof(scramble)))
    return CR_ERROR;

  if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
    return CR_ERROR;

  if (!pkt_len || (pkt_len == 1 && *pkt == 0)) /* sic! */
  {
    if (info->auth_string_length == 0)
      return CR_OK;
    return CR_AUTH_USER_CREDENTIALS;
  }
  info->password_used= PASSWORD_USED_YES;

  if (info->auth_string_length == 0)
    return CR_AUTH_USER_CREDENTIALS;

  if (pkt_len != SHA256_DIGEST_LENGTH)
    return CR_ERROR;

  /*
    TODO support caching: user@host -> plaintext password
    but for now - request full auth unconditionally
  */


  if (vio->write_packet(vio, &perform_full_authentication, 1))
    return CR_ERROR;
  
  if ((pkt_len= vio->read_packet(vio, &pkt)) <= 0)
    return CR_ERROR;

  vio->info(vio, &vio_info);
  /* secure transport, as in MySQL. SSL is "secure" even if not verified */
  if (vio_info.protocol ==  MYSQL_VIO_TCP && !vio_info.tls)
  {
    if (!private_key || !public_key_len)
    {
      my_printf_error(1, SELF ": Authentication requires either RSA keys "
                      "or secure transport", ME_ERROR_LOG_ONLY);
      return CR_AUTH_PLUGIN_ERROR;
    }

    if (pkt_len == 1 && *pkt == request_public_key)
    {
      if (vio->write_packet(vio, (unsigned char *)public_key,
                            (int)public_key_len))
        return CR_ERROR;
      if ((pkt_len= vio->read_packet(vio, &pkt)) <= 0)
        return CR_ERROR;
    }

    if (ssl_decrypt(private_key, pkt, pkt_len, plain_text, &plain_text_len))
      return CR_ERROR;

    for (size_t i=0; i < plain_text_len; i++)
      plain_text[i]^= scramble[i % SCRAMBLE_LENGTH];
    pkt= plain_text;
    pkt_len= (int)plain_text_len;
    if (pkt_len <= 0 || pkt[pkt_len-1])
      return CR_ERROR;
  }
  /* now pkt contains plaintext password */

  authstr= (struct digest*)info->auth_string;
  sha256_crypt_r(pkt, pkt_len-1, authstr->salt, sizeof(authstr->salt),
                 to, authstr->iterations);

  if (memcmp(to, authstr->crypted, SHA256CRYPT_LEN))
    return CR_AUTH_USER_CREDENTIALS;
  return CR_OK;
}

static int password_hash(const char *password, size_t password_length,
                         char *hash, size_t *hash_length)
{
  struct digest authstr;

  if (*hash_length < PASSWORD_LEN)
    return 1;

  if (!password_length)
    return (int)(*hash_length= 0);

  make_salt(authstr.salt);
  sha256_crypt_r((unsigned char*)password, password_length,
                 authstr.salt, sizeof(authstr.salt),
                 authstr.crypted, digest_rounds);
  *hash_length= my_snprintf(hash, *hash_length, "$A$%03X$%.20s%.43s",
                            digest_rounds/ITERATION_MULTIPLIER,
                            authstr.salt, authstr.crypted);
  assert(*hash_length == PASSWORD_LEN);
  return 0;
}

static int digest_to_binary(const char *hash, size_t hash_length,
                            unsigned char *out, size_t *out_length)
{
  struct digest *authstr= (struct digest*)out;
  assert(*out_length > sizeof(*authstr));
  *out_length= sizeof(*authstr);
  memset(out, 0, *out_length);
  if (hash_length != PASSWORD_LEN)
  {
    my_printf_error(ER_PASSWD_LENGTH, "Password hash should be "
                    "%zu characters long", 0, PASSWORD_LEN);
    return 1;
  }
  if (sscanf(hash, "$A$%X$%20c%43c", &authstr->iterations, authstr->salt,
             authstr->crypted) < 3)
  {
    my_printf_error(ER_PASSWD_LENGTH, "Invalid password hash", 0);
    return 1;
  }
  authstr->iterations*= ITERATION_MULTIPLIER;
  return 0;
}

static struct st_mysql_auth info=
{
  MYSQL_AUTHENTICATION_INTERFACE_VERSION,
  SELF, auth, password_hash, digest_to_binary
};

static MYSQL_SYSVAR_STR(private_key_path, private_key_path, PLUGIN_VAR_READONLY,
    "A path to the private RSA key used for authentication",
    NULL, NULL, "private_key.pem");

static MYSQL_SYSVAR_STR(public_key_path, public_key_path, PLUGIN_VAR_READONLY,
    "A path to the public RSA key used for authentication",
    NULL, NULL, "public_key.pem");

static MYSQL_SYSVAR_BOOL(auto_generate_rsa_keys, auto_generate_keys,
    PLUGIN_VAR_READONLY | PLUGIN_VAR_OPCMDARG,
    "Auto generate RSA keys at server startup if key paths "
    "are not explicitly set and key files are not present "
    "at their default locations", NULL, NULL, 1);

static MYSQL_SYSVAR_UINT(digest_rounds, digest_rounds, PLUGIN_VAR_READONLY,
  "Number of SHA2 rounds to be performed when computing a password hash",
  NULL, NULL, 5000, 5000, 0xfff * ITERATION_MULTIPLIER, 1);

static int init_keys(void *p)
{
  if (private_key_path == MYSQL_SYSVAR_NAME(private_key_path).def_val &&
      public_key_path == MYSQL_SYSVAR_NAME(public_key_path).def_val &&
      access(private_key_path, F_OK) && access(public_key_path, F_OK) &&
      auto_generate_keys)
    ssl_genkeys();
  ssl_loadkeys();
  return 0;
}

static int free_keys(void *p)
{
  EVP_PKEY_free(private_key);
  return 0;
}

static struct st_mysql_sys_var *sysvars[]=
{
  MYSQL_SYSVAR(private_key_path),
  MYSQL_SYSVAR(public_key_path),
  MYSQL_SYSVAR(auto_generate_rsa_keys),
  MYSQL_SYSVAR(digest_rounds),
  NULL
};

static struct st_mysql_show_var status_variables[]=
{
  {"rsa_public_key", public_key, SHOW_CHAR},
  {NULL, NULL, 0}
};

maria_declare_plugin(auth_mysql_sha2)
{
  MYSQL_AUTHENTICATION_PLUGIN,
  &info,
  SELF,
  "Oracle Corporation, Sergei Golubchik",
  "MySQL-compatible SHA2 authentication",
  PLUGIN_LICENSE_GPL,
  init_keys,
  free_keys,
  0x0100,
  status_variables,
  sysvars,
  "1.0",
  MariaDB_PLUGIN_MATURITY_STABLE
}
maria_declare_plugin_end;

Messung V0.5 in Prozent
C=98 H=97 G=97

¤ Dauer der Verarbeitung: 0.43 Sekunden  (vorverarbeitet am  2026-10-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1126438
#Domains=1897691