Files
ncpfs/lib/ds/setkeys.c
2026-04-28 20:56:03 +02:00

559 lines
14 KiB
C

/*
setkeys.c - NWDSGenerateObjectKeyPair implementation
Copyright (C) 2000 Petr Vandrovec
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; either version 2 of the License, or
(at your option) any later version.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Revision history:
1.00 2000, April 15 Petr Vandrovec <vandrove@vc.cvut.cz>
Initial release.
1.01 2000, April 17 Petr Vandrovec <vandrove@vc.cvut.cz>
Added NWDSVerifyObjectPassword.
1.02 2000, April 23 Petr Vandrovec <vandrove@vc.cvut.cz>
Added NWDSChangeObjectPassword. Moved nds_login from ndslib
here.
1.03 2000, May 22 Petr Vandrovec <vandrove@vc.cvut.cz>
Fixed NWDSChangeObjectPassword. It generated wrong key type.
1.04 2000, July 7 Petr Vandrovec <vandrove@vc.cvut.cz>
Modified nds_login to use unaliased name in NWDSSetKeys.
*/
#include "config.h"
#include <stddef.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include "ncplib_i.h"
#include "nwnet_i.h"
#include "ndslib_i.h"
#include "ndscrypt.h"
static NWDSCCODE __NWDSSetKeysV0(
NWCONN_HANDLE conn,
NWObjectID objectID,
Buf_T* keyPair) {
NW_FRAGMENT rq_frag[2];
nuint8 rq_b[12];
size_t len;
rq_frag[1].fragAddr.ro = NWDSBufRetrieve(keyPair, &len);
rq_frag[1].fragSize = len;
DSET_LH(rq_b, 0, 0);
DSET_HL(rq_b, 4, objectID);
DSET_LH(rq_b, 8, len);
rq_frag[0].fragAddr.ro = rq_b;
rq_frag[0].fragSize = sizeof(rq_b);
return NWCFragmentRequest(conn, DSV_SET_KEYS, 2, rq_frag, 0, NULL, NULL);
}
static NWDSCCODE __NWDSVerifyPasswordV1(
NWCONN_HANDLE conn,
NWObjectID objectID,
Buf_T* key) {
NW_FRAGMENT rq_frag[2];
nuint8 rq_b[12];
size_t len;
rq_frag[1].fragAddr.ro = NWDSBufRetrieve(key, &len);
rq_frag[1].fragSize = len;
DSET_LH(rq_b, 0, 1);
DSET_HL(rq_b, 4, objectID);
DSET_LH(rq_b, 8, len);
rq_frag[0].fragAddr.ro = rq_b;
rq_frag[0].fragSize = sizeof(rq_b);
return NWCFragmentRequest(conn, DSV_VERIFY_PASSWORD, 2, rq_frag, 0, NULL, NULL);
}
static NWDSCCODE __NWDSChangePasswordV0(
NWCONN_HANDLE conn,
NWObjectID objectID,
Buf_T* key) {
NW_FRAGMENT rq_frag[2];
nuint8 rq_b[12];
size_t len;
rq_frag[1].fragAddr.ro = NWDSBufRetrieve(key, &len);
rq_frag[1].fragSize = len;
DSET_LH(rq_b, 0, 0);
DSET_HL(rq_b, 4, objectID);
DSET_LH(rq_b, 8, len);
rq_frag[0].fragAddr.ro = rq_b;
rq_frag[0].fragSize = sizeof(rq_b);
return NWCFragmentRequest(conn, DSV_CHANGE_PASSWORD, 2, rq_frag, 0, NULL, NULL);
}
static NWDSCCODE __NWDSGenerateObjectKeyPairStep1(
NWDSContextHandle ctx,
const NWDSChar* objectName,
NWCONN_HANDLE* conn,
NWObjectID* objectID,
NWObjectID* oldPseudoID,
nuint8 rndseed[4],
nuint8** connPublicKey
) {
NWDSCCODE err;
NWDSContextHandle unictx;
NWCONN_HANDLE lconn;
*connPublicKey = NULL;
err = NWDSResolveName2DR(ctx, objectName, DS_RESOLVE_DEREF_ALIASES | DS_RESOLVE_WRITEABLE,
&lconn, objectID);
if (err)
return err;
err = __NWDSBeginLoginV0(lconn, *objectID, oldPseudoID, rndseed);
if (err)
goto err_free_conn;
err = NWDSDuplicateContextHandle(ctx, &unictx);
if (err)
goto err_free_conn;
unictx->dck.flags = DCV_TYPELESS_NAMES | DCV_XLATE_STRINGS;
err = NWDSSetContext(unictx, DCK_LOCAL_CHARSET, "WCHAR_T//");
if (err)
goto err_free_ctx_conn;
err = __NWDSGetPublicKeyFromConnection(unictx, lconn, connPublicKey);
NWDSFreeContext(unictx);
if (err)
goto err_free_conn;
*conn = lconn;
return 0;
err_free_ctx_conn:;
NWDSFreeContext(unictx);
err_free_conn:;
NWCCCloseConn(*conn);
return err;
}
static NWDSCCODE __NWDSGenerateObjectKeyPairStep2(
NWCONN_HANDLE conn,
NWObjectID objectID,
nuint8 rndseed[4],
NWObjectID pseudoID,
size_t pwdLen,
const nuint8* pwdHash,
const nuint8* connPublicKey
) {
nuint8 privkey[4096];
size_t privkey_len;
nuint8 pubkey[4096];
size_t pubkey_len;
nuint8 ec_privkey[4096];
size_t ec_privkey_len;
NWDSCCODE err;
Buf_T *ib;
Buf_T *ob;
pubkey_len = sizeof(pubkey);
privkey_len = sizeof(privkey);
/* 0, NULL, 0 == keylen, exp, exp_len */
err = __NWGenerateKeyPair(0, NULL, 0, pubkey, &pubkey_len, privkey, &privkey_len);
if (err)
return err;
ec_privkey_len = sizeof(ec_privkey);
err = __NWEncryptWithSK(pwdHash, 16, privkey, privkey_len, ec_privkey, &ec_privkey_len);
memset(privkey, 0, sizeof(privkey));
if (err)
goto err_free_pub;
err = NWDSAllocBuf(ec_privkey_len + pubkey_len + 0x2C + 8 + 8, &ib);
if (err)
goto err_free_ec_pub;
NWDSBufPutLE32(ib, 0);
NWDSBufPut(ib, rndseed, 4);
DSET_HL(NWDSBufPutPtr(ib, 4), 0, pseudoID);
NWDSBufPutLE32(ib, pwdLen);
NWDSBufPutBuffer(ib, pwdHash, 16);
NWDSBufPutBuffer(ib, ec_privkey, ec_privkey_len);
NWDSBufPutBuffer(ib, pubkey, pubkey_len);
memset(ec_privkey, 0, sizeof(ec_privkey));
memset(pubkey, 0, sizeof(pubkey));
err = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &ob);
if (err) {
NWDSClearFreeBuf(ib);
return err;
}
err = rsa_crypt2(connPublicKey, ib, ob);
NWDSClearFreeBuf(ib);
if (!err) {
err = __NWDSSetKeysV0(conn, objectID, ob);
}
NWDSClearFreeBuf(ob);
return err;
err_free_ec_pub:;
memset(ec_privkey, 0, sizeof(ec_privkey));
err_free_pub:;
memset(pubkey, 0, sizeof(pubkey));
return err;
}
static NWDSCCODE __NWDSGenerateObjectKeyPairStep3(
NWCONN_HANDLE conn,
nuint8* connPublicKey
) {
free(connPublicKey);
NWCCCloseConn(conn);
return 0;
}
static void __NWDSHashPasswordUpper(const char* objectPassword,
NWObjectID pseudoID,
size_t pwdLen,
nuint8 pwdHash[16]
) {
nuint8 newPwd[pwdLen + 1];
size_t i;
nuint8 tmpID[4];
for (i = 0; i < pwdLen; i++)
newPwd[i] = toupper(*objectPassword++);
newPwd[i] = 0;
DSET_HL(tmpID, 0, pseudoID);
shuffle(tmpID, newPwd, pwdLen, pwdHash);
}
static void __NWDSHashPassword(const char* objectPassword,
NWObjectID pseudoID,
size_t pwdLen,
nuint8 pwdHash[16]
) {
nuint8 tmpID[4];
DSET_HL(tmpID, 0, pseudoID);
shuffle(tmpID, objectPassword, pwdLen, pwdHash);
}
static NWDSCCODE __NWDSGenerateObjectKeyPair(
NWDSContextHandle ctx,
const NWDSChar* objectName,
const char* objectPassword
) {
NWCONN_HANDLE conn;
NWObjectID objectID;
NWObjectID pseudoID;
nuint8 rndseed[4];
nuint8* serverPublicKey;
NWDSCCODE err;
size_t pwdLen;
nuint8 pwdHash[16];
err = __NWDSGenerateObjectKeyPairStep1(ctx, objectName,
&conn, &objectID, &pseudoID, rndseed,
&serverPublicKey);
if (err)
return err;
/* compute key... */
pwdLen = strlen(objectPassword);
/* BEWARE! other NWDS*Password functions do NOT uppercase password */
__NWDSHashPasswordUpper(objectPassword, pseudoID, pwdLen, pwdHash);
err = __NWDSGenerateObjectKeyPairStep2(conn, objectID,
rndseed, pseudoID, pwdLen, pwdHash,
serverPublicKey);
__NWDSGenerateObjectKeyPairStep3(conn, serverPublicKey);
return err;
}
NWDSCCODE NWDSGenerateObjectKeyPair2(
NWDSContextHandle ctx,
const NWDSChar* objectName,
NWObjectID pseudoID,
size_t pwdLen,
const nuint8* pwdHash,
UNUSED( nflag32 optionsFlag)
) {
NWCONN_HANDLE conn;
NWObjectID objectID;
NWObjectID pseudoID2;
nuint8 rndseed[4];
nuint8* serverPublicKey;
NWDSCCODE err;
err = __NWDSGenerateObjectKeyPairStep1(ctx, objectName,
&conn, &objectID, &pseudoID2, rndseed,
&serverPublicKey);
if (err)
return err;
err = __NWDSGenerateObjectKeyPairStep2(conn, objectID,
rndseed, pseudoID, pwdLen, pwdHash,
serverPublicKey);
__NWDSGenerateObjectKeyPairStep3(conn, serverPublicKey);
return err;
}
NWDSCCODE NWDSGenerateObjectKeyPair(
NWDSContextHandle ctx,
const NWDSChar* objectName,
const char* objectPassword,
nflag32 optionsFlag
) {
switch (optionsFlag) {
case 0:
case NDS_PASSWORD:
return __NWDSGenerateObjectKeyPair(ctx, objectName, objectPassword);
default:
return NWE_PARAM_INVALID;
}
}
static NWDSCCODE __NWDSVerifyObjectPasswordStep2(
NWCONN_HANDLE conn,
NWObjectID objectID,
nuint8 rndseed[4],
const nuint8* pwdHash,
const nuint8* connPublicKey
) {
nuint8* ec_privkey;
size_t ec_privkey_len;
NWDSCCODE err;
Buf_T *ib;
Buf_T *ob;
err = NWDSAllocBuf(64, &ib);
if (err)
return err;
ec_privkey = NWDSBufPutPtrLen(ib, &ec_privkey_len);
err = __NWEncryptWithSK(pwdHash, 16, rndseed, 4, ec_privkey, &ec_privkey_len);
if (err)
return err;
NWDSBufPutSkip(ib, ec_privkey_len);
err = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &ob);
if (err) {
NWDSClearFreeBuf(ib);
return err;
}
err = rsa_crypt2(connPublicKey, ib, ob);
NWDSClearFreeBuf(ib);
if (!err) {
err = __NWDSVerifyPasswordV1(conn, objectID, ob);
}
NWDSClearFreeBuf(ob);
return err;
}
NWDSCCODE NWDSVerifyObjectPassword(NWDSContextHandle ctx, UNUSED(nflag32 flags),
const NWDSChar* objectName, const char* objectPassword
) {
NWCONN_HANDLE conn;
NWObjectID objectID;
NWObjectID pseudoID;
nuint8 rndseed[4];
nuint8* serverPublicKey;
NWDSCCODE err;
size_t pwdLen;
nuint8 pwdHash[16];
err = __NWDSGenerateObjectKeyPairStep1(ctx, objectName,
&conn, &objectID, &pseudoID, rndseed,
&serverPublicKey);
if (err)
return err;
/* compute key... */
pwdLen = strlen(objectPassword);
__NWDSHashPassword(objectPassword, pseudoID, pwdLen, pwdHash);
err = __NWDSVerifyObjectPasswordStep2(conn, objectID, rndseed,
pwdHash, serverPublicKey);
__NWDSGenerateObjectKeyPairStep3(conn, serverPublicKey);
return err;
}
static NWDSCCODE __NWDSChangeObjectPasswordStep2(
NWCONN_HANDLE conn,
NWObjectID objectID,
NWObjectID pseudoID,
nuint8 rndseed[4],
nuint8 *connPublicKey,
const char* oldPassword,
const char* newPassword
) {
nuint8* privateKey;
size_t privateKeyLen;
nuint8 ec_newpwd[4096];
size_t ec_newpwd_len;
nuint8 oldPwdHash[16];
nuint8 newPwdHash[16];
NWDSCCODE err;
NWDSCCODE gpk_err;
size_t di;
Buf_T *ib;
Buf_T *ob;
nuint8 tmpID[4];
DSET_HL(tmpID, 0, pseudoID);
shuffle(tmpID, oldPassword, strlen(oldPassword), oldPwdHash);
shuffle(tmpID, newPassword, strlen(newPassword), newPwdHash);
err = __NWDSGetPrivateKey(conn, connPublicKey, rndseed, objectID, oldPwdHash, NULL, &privateKey, &privateKeyLen);
if (err != 0 && err != NWE_PASSWORD_EXPIRED)
goto quit;
if (privateKeyLen < 10) {
err = ERR_INVALID_SERVER_RESPONSE;
goto free_privkey;
}
DSET_LH(privateKey, 2, 1);
WSET_LH(privateKey, 6, 2);
gpk_err = err;
ec_newpwd_len = sizeof(ec_newpwd);
err = __NWEncryptWithSK(newPwdHash, 16, privateKey + 2, privateKeyLen - 2, ec_newpwd, &ec_newpwd_len);
if (err)
goto free_privkey;
di = ec_newpwd_len + 0x34;
err = NWDSAllocBuf(di + 8, &ib);
if (err)
goto free_privkey_ecnewpwd;
NWDSBufPut(ib, rndseed, 4);
NWDSBufPutBuffer(ib, oldPwdHash, 16);
NWDSBufPutLE32(ib, strlen(newPassword));
NWDSBufPutBuffer(ib, newPwdHash, 16);
NWDSBufPutBuffer(ib, ec_newpwd, ec_newpwd_len);
err = NWDSAllocBuf(di + 256, &ob);
if (err)
goto free_privkey_ecnewpwd_ib;
err = rsa_crypt2(connPublicKey, ib, ob);
if (err)
goto free_privkey_ecnewpwd_ib_ob;
err = __NWDSChangePasswordV0(conn, objectID, ob);
if (!err)
err = gpk_err;
free_privkey_ecnewpwd_ib_ob:;
NWDSClearFreeBuf(ob);
free_privkey_ecnewpwd_ib:;
NWDSClearFreeBuf(ib);
free_privkey_ecnewpwd:;
memset(ec_newpwd, 0, sizeof(ec_newpwd));
free_privkey:;
memset(privateKey, 0, privateKeyLen);
free(privateKey);
quit:;
memset(oldPwdHash, 0, sizeof(oldPwdHash));
memset(newPwdHash, 0, sizeof(newPwdHash));
return err;
}
static NWDSCCODE __NWDSChangeObjectPassword(
NWDSContextHandle ctx,
const NWDSChar* objectName,
const char* oldPassword,
const char* newPassword) {
NWCONN_HANDLE conn;
NWObjectID objectID;
NWObjectID pseudoID;
nuint8 rndseed[4];
nuint8* connPublicKey;
NWDSCCODE err;
err = __NWDSGenerateObjectKeyPairStep1(ctx, objectName,
&conn, &objectID, &pseudoID, rndseed,
&connPublicKey);
if (err)
return err;
err = __NWDSChangeObjectPasswordStep2(conn, objectID, pseudoID, rndseed, connPublicKey, oldPassword, newPassword);
__NWDSGenerateObjectKeyPairStep3(conn, connPublicKey);
return err;
}
NWDSCCODE NWDSChangeObjectPassword(
NWDSContextHandle ctx,
nflag32 flags,
const NWDSChar* objectName,
const char* oldPassword,
const char* newPassword
) {
switch (flags) {
case 0:
case NDS_PASSWORD:
return __NWDSChangeObjectPassword(ctx, objectName, oldPassword, newPassword);
default:
return NWE_PARAM_INVALID;
}
}
NWDSCCODE nds_login(
NWDSContextHandle ctx,
const NWDSChar* objectName,
const char *objectPassword) {
NWCONN_HANDLE conn;
NWObjectID objectID;
NWObjectID pseudoID;
nuint8 rndseed[4];
nuint8* serverPublicKey;
NWDSCCODE err;
size_t pwdLen;
nuint8 pwdHash[16];
nuint8* privKey;
size_t privKeyLen;
nuint8 logindata[8];
NWDSCCODE grace_err;
wchar_t unaliasedName[MAX_DN_CHARS + 1];
NWDSContextHandle wctx;
err = __NWDSGenerateObjectKeyPairStep1(ctx, objectName,
&conn, &objectID, &pseudoID, rndseed,
&serverPublicKey);
if (err)
return err;
err = NWDSDuplicateContextHandleInt(ctx, &wctx);
if (err) {
__NWDSGenerateObjectKeyPairStep3(conn, serverPublicKey);
return err;
}
err = NWDSMapIDToName(wctx, conn, objectID, (NWDSChar*)unaliasedName);
if (err) {
NWDSFreeContext(wctx);
__NWDSGenerateObjectKeyPairStep3(conn, serverPublicKey);
return err;
}
/* compute key... */
pwdLen = strlen(objectPassword);
/* BEWARE! other NWDS*Password functions do NOT uppercase password */
__NWDSHashPasswordUpper(objectPassword, pseudoID, pwdLen, pwdHash);
grace_err = __NWDSGetPrivateKey(conn, serverPublicKey,
rndseed, objectID, pwdHash, logindata, &privKey, &privKeyLen);
__NWDSGenerateObjectKeyPairStep3(conn, serverPublicKey);
if (!grace_err || grace_err == NWE_PASSWORD_EXPIRED) {
err = NWDSSetKeys(wctx, logindata, unaliasedName, privKey, privKeyLen);
memset(privKey, 0, privKeyLen);
free(privKey);
if (err)
goto err_exit;
}
err = grace_err;
err_exit:
NWDSFreeContext(wctx);
memset(logindata, 0, sizeof(logindata));
return err;
}