You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-11-03 17:13:17 +03:00
587 lines
17 KiB
C
587 lines
17 KiB
C
/* Portions of this file are subject to the following copyright(s). See
|
|
* the Net-SNMP's COPYING file for more details and other copyrights
|
|
* that may apply:
|
|
*/
|
|
/*
|
|
* Portions of this file are copyrighted by:
|
|
* Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
|
|
* Use is subject to license terms specified in the COPYING file
|
|
* distributed with the Net-SNMP package.
|
|
*/
|
|
|
|
/*
|
|
* keytools.c
|
|
*/
|
|
|
|
#include <net-snmp/net-snmp-config.h>
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#if HAVE_WINSOCK_H
|
|
#include <winsock.h>
|
|
#endif
|
|
#ifdef HAVE_NETINET_IN_H
|
|
#include <netinet/in.h>
|
|
#endif
|
|
#ifdef HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#else
|
|
#include <strings.h>
|
|
#endif
|
|
|
|
#if HAVE_DMALLOC_H
|
|
#include <dmalloc.h>
|
|
#endif
|
|
|
|
#include <net-snmp/types.h>
|
|
#include <net-snmp/output_api.h>
|
|
#include <net-snmp/utilities.h>
|
|
|
|
#include <net-snmp/library/snmp_api.h>
|
|
#ifdef USE_OPENSSL
|
|
# include <openssl/hmac.h>
|
|
#else
|
|
#ifdef USE_INTERNAL_MD5
|
|
#include <net-snmp/library/md5.h>
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef USE_PKCS
|
|
#include <security/cryptoki.h>
|
|
#endif
|
|
|
|
#include <net-snmp/library/scapi.h>
|
|
#include <net-snmp/library/keytools.h>
|
|
|
|
#include <net-snmp/library/transform_oids.h>
|
|
|
|
/*******************************************************************-o-******
|
|
* generate_Ku
|
|
*
|
|
* Parameters:
|
|
* *hashtype MIB OID for the transform type for hashing.
|
|
* hashtype_len Length of OID value.
|
|
* *P Pre-allocated bytes of passpharase.
|
|
* pplen Length of passphrase.
|
|
* *Ku Buffer to contain Ku.
|
|
* *kulen Length of Ku buffer.
|
|
*
|
|
* Returns:
|
|
* SNMPERR_SUCCESS Success.
|
|
* SNMPERR_GENERR All errors.
|
|
*
|
|
*
|
|
* Convert a passphrase into a master user key, Ku, according to the
|
|
* algorithm given in RFC 2274 concerning the SNMPv3 User Security Model (USM)
|
|
* as follows:
|
|
*
|
|
* Expand the passphrase to fill the passphrase buffer space, if necessary,
|
|
* concatenation as many duplicates as possible of P to itself. If P is
|
|
* larger than the buffer space, truncate it to fit.
|
|
*
|
|
* Then hash the result with the given hashtype transform. Return
|
|
* the result as Ku.
|
|
*
|
|
* If successful, kulen contains the size of the hash written to Ku.
|
|
*
|
|
* NOTE Passphrases less than USM_LENGTH_P_MIN characters in length
|
|
* cause an error to be returned.
|
|
* (Punt this check to the cmdline apps? XXX)
|
|
*/
|
|
int
|
|
generate_Ku(const oid * hashtype, u_int hashtype_len,
|
|
u_char * P, size_t pplen, u_char * Ku, size_t * kulen)
|
|
#if defined(USE_INTERNAL_MD5) || defined(USE_OPENSSL)
|
|
{
|
|
int rval = SNMPERR_SUCCESS,
|
|
nbytes = USM_LENGTH_EXPANDED_PASSPHRASE;
|
|
|
|
u_int i, pindex = 0;
|
|
|
|
u_char buf[USM_LENGTH_KU_HASHBLOCK], *bufp;
|
|
|
|
#ifdef USE_OPENSSL
|
|
EVP_MD_CTX *ctx = malloc(sizeof(EVP_MD_CTX));
|
|
#else
|
|
MDstruct MD;
|
|
#endif
|
|
/*
|
|
* Sanity check.
|
|
*/
|
|
if (!hashtype || !P || !Ku || !kulen || (*kulen <= 0)
|
|
|| (hashtype_len != USM_LENGTH_OID_TRANSFORM)) {
|
|
QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
|
|
}
|
|
|
|
if (pplen < USM_LENGTH_P_MIN) {
|
|
snmp_log(LOG_ERR, "Error: passphrase chosen is below the length "
|
|
"requirements of the USM (min=%d).\n",USM_LENGTH_P_MIN);
|
|
snmp_set_detail("The supplied password length is too short.");
|
|
QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
|
|
}
|
|
|
|
|
|
/*
|
|
* Setup for the transform type.
|
|
*/
|
|
#ifdef USE_OPENSSL
|
|
|
|
#ifndef DISABLE_MD5
|
|
if (ISTRANSFORM(hashtype, HMACMD5Auth))
|
|
EVP_DigestInit(ctx, EVP_md5());
|
|
else
|
|
#endif
|
|
if (ISTRANSFORM(hashtype, HMACSHA1Auth))
|
|
EVP_DigestInit(ctx, EVP_sha1());
|
|
else {
|
|
free(ctx);
|
|
return (SNMPERR_GENERR);
|
|
}
|
|
#else
|
|
MDbegin(&MD);
|
|
#endif /* USE_OPENSSL */
|
|
|
|
while (nbytes > 0) {
|
|
bufp = buf;
|
|
for (i = 0; i < USM_LENGTH_KU_HASHBLOCK; i++) {
|
|
*bufp++ = P[pindex++ % pplen];
|
|
}
|
|
#ifdef USE_OPENSSL
|
|
EVP_DigestUpdate(ctx, buf, USM_LENGTH_KU_HASHBLOCK);
|
|
#elif USE_INTERNAL_MD5
|
|
if (MDupdate(&MD, buf, USM_LENGTH_KU_HASHBLOCK * 8)) {
|
|
rval = SNMPERR_USM_ENCRYPTIONERROR;
|
|
goto md5_fin;
|
|
}
|
|
#endif /* USE_OPENSSL */
|
|
|
|
nbytes -= USM_LENGTH_KU_HASHBLOCK;
|
|
}
|
|
|
|
#ifdef USE_OPENSSL
|
|
EVP_DigestFinal(ctx, (unsigned char *) Ku, (unsigned int *) kulen);
|
|
/*
|
|
* what about free()
|
|
*/
|
|
#elif USE_INTERNAL_MD5
|
|
if (MDupdate(&MD, buf, 0)) {
|
|
rval = SNMPERR_USM_ENCRYPTIONERROR;
|
|
goto md5_fin;
|
|
}
|
|
*kulen = sc_get_properlength(hashtype, hashtype_len);
|
|
MDget(&MD, Ku, *kulen);
|
|
md5_fin:
|
|
memset(&MD, 0, sizeof(MD));
|
|
#endif /* USE_INTERNAL_MD5 */
|
|
|
|
|
|
#ifdef SNMP_TESTING_CODE
|
|
DEBUGMSGTL(("generate_Ku", "generating Ku (from %s): ", P));
|
|
for (i = 0; i < *kulen; i++)
|
|
DEBUGMSG(("generate_Ku", "%02x", Ku[i]));
|
|
DEBUGMSG(("generate_Ku", "\n"));
|
|
#endif /* SNMP_TESTING_CODE */
|
|
|
|
|
|
generate_Ku_quit:
|
|
memset(buf, 0, sizeof(buf));
|
|
#ifdef USE_OPENSSL
|
|
free(ctx);
|
|
#endif
|
|
return rval;
|
|
|
|
} /* end generate_Ku() */
|
|
#elif USE_PKCS
|
|
{
|
|
int rval = SNMPERR_SUCCESS;
|
|
|
|
/*
|
|
* Sanity check.
|
|
*/
|
|
if (!hashtype || !P || !Ku || !kulen || (*kulen <= 0)
|
|
|| (hashtype_len != USM_LENGTH_OID_TRANSFORM)) {
|
|
QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
|
|
}
|
|
|
|
if (pplen < USM_LENGTH_P_MIN) {
|
|
snmp_log(LOG_ERR, "Error: passphrase chosen is below the length "
|
|
"requirements of the USM (min=%d).\n",USM_LENGTH_P_MIN);
|
|
snmp_set_detail("The supplied password length is too short.");
|
|
QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
|
|
}
|
|
|
|
/*
|
|
* Setup for the transform type.
|
|
*/
|
|
|
|
#ifndef DISABLE_MD5
|
|
if (ISTRANSFORM(hashtype, HMACMD5Auth))
|
|
return pkcs_generate_Ku(CKM_MD5, P, pplen, Ku, kulen);
|
|
else
|
|
#endif
|
|
if (ISTRANSFORM(hashtype, HMACSHA1Auth))
|
|
return pkcs_generate_Ku(CKM_SHA_1, P, pplen, Ku, kulen);
|
|
else {
|
|
return (SNMPERR_GENERR);
|
|
}
|
|
|
|
generate_Ku_quit:
|
|
|
|
return rval;
|
|
} /* end generate_Ku() */
|
|
#else
|
|
_KEYTOOLS_NOT_AVAILABLE
|
|
#endif /* internal or openssl */
|
|
/*******************************************************************-o-******
|
|
* generate_kul
|
|
*
|
|
* Parameters:
|
|
* *hashtype
|
|
* hashtype_len
|
|
* *engineID
|
|
* engineID_len
|
|
* *Ku Master key for a given user.
|
|
* ku_len Length of Ku in bytes.
|
|
* *Kul Localized key for a given user at engineID.
|
|
* *kul_len Length of Kul buffer (IN); Length of Kul key (OUT).
|
|
*
|
|
* Returns:
|
|
* SNMPERR_SUCCESS Success.
|
|
* SNMPERR_GENERR All errors.
|
|
*
|
|
*
|
|
* Ku MUST be the proper length (currently fixed) for the given hashtype.
|
|
*
|
|
* Upon successful return, Kul contains the localized form of Ku at
|
|
* engineID, and the length of the key is stored in kul_len.
|
|
*
|
|
* The localized key method is defined in RFC2274, Sections 2.6 and A.2, and
|
|
* originally documented in:
|
|
* U. Blumenthal, N. C. Hien, B. Wijnen,
|
|
* "Key Derivation for Network Management Applications",
|
|
* IEEE Network Magazine, April/May issue, 1997.
|
|
*
|
|
*
|
|
* ASSUMES SNMP_MAXBUF >= sizeof(Ku + engineID + Ku).
|
|
*
|
|
* NOTE Localized keys for privacy transforms are generated via
|
|
* the authentication transform held by the same usmUser.
|
|
*
|
|
* XXX An engineID of any length is accepted, even if larger than
|
|
* what is spec'ed for the textual convention.
|
|
*/
|
|
int
|
|
generate_kul(const oid * hashtype, u_int hashtype_len,
|
|
u_char * engineID, size_t engineID_len,
|
|
u_char * Ku, size_t ku_len,
|
|
u_char * Kul, size_t * kul_len)
|
|
#if defined(USE_OPENSSL) || defined(USE_INTERNAL_MD5) || defined(USE_PKCS)
|
|
{
|
|
int rval = SNMPERR_SUCCESS;
|
|
u_int nbytes = 0;
|
|
size_t properlength;
|
|
|
|
u_char buf[SNMP_MAXBUF];
|
|
#ifdef SNMP_TESTING_CODE
|
|
int i;
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Sanity check.
|
|
*/
|
|
if (!hashtype || !engineID || !Ku || !Kul || !kul_len
|
|
|| (engineID_len <= 0) || (ku_len <= 0) || (*kul_len <= 0)
|
|
|| (hashtype_len != USM_LENGTH_OID_TRANSFORM)) {
|
|
QUITFUN(SNMPERR_GENERR, generate_kul_quit);
|
|
}
|
|
|
|
|
|
properlength = sc_get_properlength(hashtype, hashtype_len);
|
|
if (properlength == SNMPERR_GENERR)
|
|
QUITFUN(SNMPERR_GENERR, generate_kul_quit);
|
|
|
|
|
|
if (((int) *kul_len < properlength) || ((int) ku_len < properlength)) {
|
|
QUITFUN(SNMPERR_GENERR, generate_kul_quit);
|
|
}
|
|
|
|
/*
|
|
* Concatenate Ku and engineID properly, then hash the result.
|
|
* Store it in Kul.
|
|
*/
|
|
nbytes = 0;
|
|
memcpy(buf, Ku, properlength);
|
|
nbytes += properlength;
|
|
memcpy(buf + nbytes, engineID, engineID_len);
|
|
nbytes += engineID_len;
|
|
memcpy(buf + nbytes, Ku, properlength);
|
|
nbytes += properlength;
|
|
|
|
rval = sc_hash(hashtype, hashtype_len, buf, nbytes, Kul, kul_len);
|
|
|
|
#ifdef SNMP_TESTING_CODE
|
|
DEBUGMSGTL(("generate_kul", "generating Kul (from Ku): "));
|
|
for (i = 0; i < *kul_len; i++)
|
|
DEBUGMSG(("generate_kul", "%02x", Kul[i]));
|
|
DEBUGMSG(("generate_kul", "keytools\n"));
|
|
#endif /* SNMP_TESTING_CODE */
|
|
|
|
QUITFUN(rval, generate_kul_quit);
|
|
|
|
|
|
generate_kul_quit:
|
|
return rval;
|
|
|
|
} /* end generate_kul() */
|
|
|
|
#else
|
|
_KEYTOOLS_NOT_AVAILABLE
|
|
#endif /* internal or openssl */
|
|
/*******************************************************************-o-******
|
|
* encode_keychange
|
|
*
|
|
* Parameters:
|
|
* *hashtype MIB OID for the hash transform type.
|
|
* hashtype_len Length of the MIB OID hash transform type.
|
|
* *oldkey Old key that is used to encodes the new key.
|
|
* oldkey_len Length of oldkey in bytes.
|
|
* *newkey New key that is encoded using the old key.
|
|
* newkey_len Length of new key in bytes.
|
|
* *kcstring Buffer to contain the KeyChange TC string.
|
|
* *kcstring_len Length of kcstring buffer.
|
|
*
|
|
* Returns:
|
|
* SNMPERR_SUCCESS Success.
|
|
* SNMPERR_GENERR All errors.
|
|
*
|
|
*
|
|
* Uses oldkey and acquired random bytes to encode newkey into kcstring
|
|
* according to the rules of the KeyChange TC described in RFC 2274, Section 5.
|
|
*
|
|
* Upon successful return, *kcstring_len contains the length of the
|
|
* encoded string.
|
|
*
|
|
* ASSUMES Old and new key are always equal to each other, although
|
|
* this may be less than the transform type hash output
|
|
* output length (eg, using KeyChange for a DESPriv key when
|
|
* the user also uses SHA1Auth). This also implies that the
|
|
* hash placed in the second 1/2 of the key change string
|
|
* will be truncated before the XOR'ing when the hash output is
|
|
* larger than that 1/2 of the key change string.
|
|
*
|
|
* *kcstring_len will be returned as exactly twice that same
|
|
* length though the input buffer may be larger.
|
|
*
|
|
* XXX FIX: Does not handle varibable length keys.
|
|
* XXX FIX: Does not handle keys larger than the hash algorithm used.
|
|
*/
|
|
int
|
|
encode_keychange(const oid * hashtype, u_int hashtype_len,
|
|
u_char * oldkey, size_t oldkey_len,
|
|
u_char * newkey, size_t newkey_len,
|
|
u_char * kcstring, size_t * kcstring_len)
|
|
#if defined(USE_OPENSSL) || defined(USE_INTERNAL_MD5) || defined(USE_PKCS)
|
|
{
|
|
int rval = SNMPERR_SUCCESS;
|
|
size_t properlength;
|
|
size_t nbytes = 0;
|
|
|
|
u_char *tmpbuf = NULL;
|
|
|
|
|
|
/*
|
|
* Sanity check.
|
|
*/
|
|
if (!hashtype || !oldkey || !newkey || !kcstring || !kcstring_len
|
|
|| (oldkey_len <= 0) || (newkey_len <= 0) || (*kcstring_len <= 0)
|
|
|| (hashtype_len != USM_LENGTH_OID_TRANSFORM)) {
|
|
QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
|
|
}
|
|
|
|
/*
|
|
* Setup for the transform type.
|
|
*/
|
|
properlength = sc_get_properlength(hashtype, hashtype_len);
|
|
if (properlength == SNMPERR_GENERR)
|
|
QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
|
|
|
|
if ((oldkey_len != newkey_len) || (*kcstring_len < (2 * oldkey_len))) {
|
|
QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
|
|
}
|
|
|
|
properlength = SNMP_MIN((int) oldkey_len, properlength);
|
|
|
|
/*
|
|
* Use the old key and some random bytes to encode the new key
|
|
* in the KeyChange TC format:
|
|
* . Get random bytes (store in first half of kcstring),
|
|
* . Hash (oldkey | random_bytes) (into second half of kcstring),
|
|
* . XOR hash and newkey (into second half of kcstring).
|
|
*
|
|
* Getting the wrong number of random bytes is considered an error.
|
|
*/
|
|
nbytes = properlength;
|
|
|
|
#if defined(SNMP_TESTING_CODE) && defined(RANDOMZEROS)
|
|
memset(kcstring, 0, nbytes);
|
|
DEBUGMSG(("encode_keychange",
|
|
"** Using all zero bits for \"random\" delta of )"
|
|
"the keychange string! **\n"));
|
|
#else /* !SNMP_TESTING_CODE */
|
|
rval = sc_random(kcstring, &nbytes);
|
|
QUITFUN(rval, encode_keychange_quit);
|
|
if ((int) nbytes != properlength) {
|
|
QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
|
|
}
|
|
#endif /* !SNMP_TESTING_CODE */
|
|
|
|
tmpbuf = (u_char *) malloc(properlength * 2);
|
|
if (tmpbuf) {
|
|
memcpy(tmpbuf, oldkey, properlength);
|
|
memcpy(tmpbuf + properlength, kcstring, properlength);
|
|
|
|
*kcstring_len -= properlength;
|
|
rval = sc_hash(hashtype, hashtype_len, tmpbuf, properlength * 2,
|
|
kcstring + properlength, kcstring_len);
|
|
|
|
QUITFUN(rval, encode_keychange_quit);
|
|
|
|
*kcstring_len = (properlength * 2);
|
|
|
|
kcstring += properlength;
|
|
nbytes = 0;
|
|
while ((int) (nbytes++) < properlength) {
|
|
*kcstring++ ^= *newkey++;
|
|
}
|
|
}
|
|
|
|
encode_keychange_quit:
|
|
if (rval != SNMPERR_SUCCESS)
|
|
memset(kcstring, 0, *kcstring_len);
|
|
SNMP_FREE(tmpbuf);
|
|
|
|
return rval;
|
|
|
|
} /* end encode_keychange() */
|
|
|
|
#else
|
|
_KEYTOOLS_NOT_AVAILABLE
|
|
#endif /* internal or openssl */
|
|
/*******************************************************************-o-******
|
|
* decode_keychange
|
|
*
|
|
* Parameters:
|
|
* *hashtype MIB OID of the hash transform to use.
|
|
* hashtype_len Length of the hash transform MIB OID.
|
|
* *oldkey Old key that is used to encode the new key.
|
|
* oldkey_len Length of oldkey in bytes.
|
|
* *kcstring Encoded KeyString buffer containing the new key.
|
|
* kcstring_len Length of kcstring in bytes.
|
|
* *newkey Buffer to hold the extracted new key.
|
|
* *newkey_len Length of newkey in bytes.
|
|
*
|
|
* Returns:
|
|
* SNMPERR_SUCCESS Success.
|
|
* SNMPERR_GENERR All errors.
|
|
*
|
|
*
|
|
* Decodes a string of bits encoded according to the KeyChange TC described
|
|
* in RFC 2274, Section 5. The new key is extracted from *kcstring with
|
|
* the aid of the old key.
|
|
*
|
|
* Upon successful return, *newkey_len contains the length of the new key.
|
|
*
|
|
*
|
|
* ASSUMES Old key is exactly 1/2 the length of the KeyChange buffer,
|
|
* although this length may be less than the hash transform
|
|
* output. Thus the new key length will be equal to the old
|
|
* key length.
|
|
*/
|
|
/*
|
|
* XXX: if the newkey is not long enough, it should be freed and remalloced
|
|
*/
|
|
int
|
|
decode_keychange(const oid * hashtype, u_int hashtype_len,
|
|
u_char * oldkey, size_t oldkey_len,
|
|
u_char * kcstring, size_t kcstring_len,
|
|
u_char * newkey, size_t * newkey_len)
|
|
#if defined(USE_OPENSSL) || defined(USE_INTERNAL_MD5) || defined(USE_PKCS)
|
|
{
|
|
int rval = SNMPERR_SUCCESS;
|
|
size_t properlength = 0;
|
|
u_int nbytes = 0;
|
|
|
|
u_char *bufp, tmp_buf[SNMP_MAXBUF];
|
|
size_t tmp_buf_len = SNMP_MAXBUF;
|
|
u_char *tmpbuf = NULL;
|
|
|
|
|
|
|
|
/*
|
|
* Sanity check.
|
|
*/
|
|
if (!hashtype || !oldkey || !kcstring || !newkey || !newkey_len
|
|
|| (oldkey_len <= 0) || (kcstring_len <= 0) || (*newkey_len <= 0)
|
|
|| (hashtype_len != USM_LENGTH_OID_TRANSFORM)) {
|
|
QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
|
|
}
|
|
|
|
|
|
/*
|
|
* Setup for the transform type.
|
|
*/
|
|
properlength = sc_get_properlength(hashtype, hashtype_len);
|
|
if (properlength == SNMPERR_GENERR)
|
|
QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
|
|
|
|
|
|
if (((oldkey_len * 2) != kcstring_len) || (*newkey_len < oldkey_len)) {
|
|
QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
|
|
}
|
|
|
|
properlength = oldkey_len;
|
|
*newkey_len = properlength;
|
|
|
|
/*
|
|
* Use the old key and the given KeyChange TC string to recover
|
|
* the new key:
|
|
* . Hash (oldkey | random_bytes) (into newkey),
|
|
* . XOR hash and encoded (second) half of kcstring (into newkey).
|
|
*/
|
|
tmpbuf = (u_char *) malloc(properlength * 2);
|
|
if (tmpbuf) {
|
|
memcpy(tmpbuf, oldkey, properlength);
|
|
memcpy(tmpbuf + properlength, kcstring, properlength);
|
|
|
|
rval = sc_hash(hashtype, hashtype_len, tmpbuf, properlength * 2,
|
|
tmp_buf, &tmp_buf_len);
|
|
QUITFUN(rval, decode_keychange_quit);
|
|
|
|
memcpy(newkey, tmp_buf, properlength);
|
|
bufp = kcstring + properlength;
|
|
nbytes = 0;
|
|
while ((int) (nbytes++) < properlength) {
|
|
*newkey++ ^= *bufp++;
|
|
}
|
|
}
|
|
|
|
decode_keychange_quit:
|
|
if (rval != SNMPERR_SUCCESS) {
|
|
memset(newkey, 0, properlength);
|
|
}
|
|
memset(tmp_buf, 0, SNMP_MAXBUF);
|
|
if (tmpbuf != NULL)
|
|
SNMP_FREE(tmpbuf);
|
|
|
|
return rval;
|
|
|
|
} /* end decode_keychange() */
|
|
|
|
#else
|
|
_KEYTOOLS_NOT_AVAILABLE
|
|
#endif /* internal or openssl */
|