Projekt

Allgemein

Profil

Feature #43 » aqbanking-change-keys.patch

thbe, 11.09.2019 18:57

Unterschiede anzeigen:

src/libs/plugins/backends/aqhbci/admjobs/Makefile.am
noinst_HEADERS=\
jobgetkeys_l.h jobgetkeys_p.h \
jobsendkeys_l.h jobsendkeys_p.h \
jobchangekeys_l.h jobchangekeys_p.h \
jobtan_l.h jobtan_p.h \
jobgetsepainfo_l.h jobgetsepainfo_p.h \
jobgetsysid_l.h jobgetsysid_p.h \
......
libhbciadmjobs_la_SOURCES=\
jobgetkeys.c \
jobsendkeys.c \
jobchangekeys.c \
jobtan.c \
jobgetsepainfo.c \
jobgetsysid.c \
......
xmlfiles=\
$(srcdir)/jobgetkeys.xml \
$(srcdir)/jobsendkeys.xml \
$(srcdir)/jobchangekeys.xml \
$(srcdir)/jobtan.xml \
$(srcdir)/jobgetsepainfo.xml \
$(srcdir)/jobgetsysid.xml \
src/libs/plugins/backends/aqhbci/admjobs/jobchangekeys.c
/***************************************************************************
***************************************************************************
* Please see toplevel file COPYING for license details *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "jobchangekeys_p.h"
#include "../banking/user_l.h"
#include "../banking/provider_l.h"
#include <gwenhywfar/ctplugin.h>
#include <gwenhywfar/ctfile_be.h>
#include <stdarg.h>
#include <unistd.h>
/*
Mögliche Wechsel:
medium type mode
datei RDH 1 karte o. cert RAH 9
datei RDH 1 datei RAH 10
karte o. cert RDH 1 karte o. cert RAH 9
datei RDH 2 karte o. cert RAH 9
datei RDH 2 datei RAH 10
karte o. cert RDH 5 karte o. cert RAH 9
ohne Schlüsselwechsel:
karte o. cert RDH 9 karte o. cert RAH 9
datei RDH 10 karte o. cert RAH 9
datei RDH 10 datei RAH 10
*/
GWEN_INHERIT(AH_JOB, AH_JOB_CHANGEKEYS)
const char *fmtStr(char *buff, size_t buffLen, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
const char *fmtStr(char *buff, size_t buffLen, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vsnprintf(buff, buffLen - 1, fmt, args);
buff[buffLen - 1] = 0;
va_end(args);
return buff;
}
#define FB fmtBuff, sizeof(fmtBuff)
int onError(const char *m, int rv)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s", m);
GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_ERROR,
I18N("Change keys: error"), I18N(m), I18N("OK"), NULL, NULL, 0);
return rv;
}
struct AH_JOB_CHANGEKEYS
{
uint16_t flags;
uint8_t *canceled;
AB_PROVIDER *pro;
AB_USER *u;
AB_USER *uTmp;
const char *fm;
char *tt, *tn;
uint32_t kvVCurr, kvSCurr, kvACurr;
GWEN_CRYPT_TOKEN *ct;
const GWEN_CRYPT_TOKEN_CONTEXT *ctx;
int tokenCtxId;
const GWEN_CRYPT_TOKEN_KEYINFO *kiV, *kiS, *kiA;
int8_t resp;
GWEN_BUFFER *emsg;
};
const char *strUpper(char *s)
{
size_t l = strlen(s);
for(size_t i = 0; i < l; i++)
{
if((s[i] >= 'a') && (s[i] <= 'z'))
s[i] -= 0x20;
}
return s;
}
int8_t getKeyInfo(AH_HBCI *h, const char *tt, const char *tn, uint32_t cid, GWEN_CRYPT_TOKEN **ct, const GWEN_CRYPT_TOKEN_CONTEXT **ctx,
const GWEN_CRYPT_TOKEN_KEYINFO **kiV, const GWEN_CRYPT_TOKEN_KEYINFO **kiS, const GWEN_CRYPT_TOKEN_KEYINFO **kiA)
{
int8_t res = 0;
uint32_t f = GWEN_CRYPT_TOKEN_KEYFLAGS_HASMODULUS | GWEN_CRYPT_TOKEN_KEYFLAGS_HASEXPONENT |
GWEN_CRYPT_TOKEN_KEYFLAGS_HASKEYVERSION | GWEN_CRYPT_TOKEN_KEYFLAGS_HASKEYNUMBER;
if(!*ct && (((AB_Banking_GetCryptToken(AH_HBCI_GetBankingApi(h), tt, tn, ct) < 0)) || !*ct))
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "AB_Banking_GetCryptToken() failed (tt '%s', tn '%s').", tt, tn);
return -1;
}
if(GWEN_Crypt_Token_Open(*ct, 0, 0) < 0)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "GWEN_Crypt_Token_Open() failed.");
return -1;
}
*ctx = GWEN_Crypt_Token_GetContext(*ct, cid, 0);
if(!*ctx)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "GWEN_Crypt_Token_GetContext() failed (cid %ld).", (long)cid);
return -1;
}
for(uint8_t i = 0; i < 3; i++)
{
uint32_t kid = 0;
const GWEN_CRYPT_TOKEN_KEYINFO **ki = NULL;
char kl = '?';
switch(i)
{
case 0: kid = GWEN_Crypt_Token_Context_GetDecipherKeyId(*ctx); ki = kiV, kl = 'V'; break;
case 1: kid = GWEN_Crypt_Token_Context_GetSignKeyId(*ctx); ki = kiS; kl = 'S'; break;
case 2: kid = GWEN_Crypt_Token_Context_GetAuthSignKeyId(*ctx); ki = kiA; kl = 'D'; break;
}
if((kl == 'D') && !strcmp(tt, "ddvcard"))
continue;
if((*ki = GWEN_Crypt_Token_GetKeyInfo(*ct, kid, f, 0)) == NULL)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "GWEN_Crypt_Token_GetKeyInfo() (%c) failed.", kl);
res = -1;
break;
}
}
return res;
}
int8_t tokenHasKeys(GWEN_CRYPT_TOKEN *ct, const GWEN_CRYPT_TOKEN_CONTEXT *ctx)
{
int8_t res = 2;
for(uint8_t i = 0; (res > 0) && (i < 2); i++)
{
const GWEN_CRYPT_TOKEN_KEYINFO *ki = NULL;
int kn = 0, kv = 0;
uint32_t flags = 0;
uint32_t id = (i == 0) ? GWEN_Crypt_Token_Context_GetDecipherKeyId(ctx) : GWEN_Crypt_Token_Context_GetVerifyKeyId(ctx);
if(res == 2)
res = 1;
if(!id)
res = -1;
else
ki = GWEN_Crypt_Token_GetKeyInfo(ct, id, 0, 0);
if(!ki)
res = -1;
else
{
kn = GWEN_Crypt_Token_KeyInfo_GetKeyNumber(ki);
kv = GWEN_Crypt_Token_KeyInfo_GetKeyVersion(ki);
flags = GWEN_Crypt_Token_KeyInfo_GetFlags(ki);
}
if((res >= 0) && (!kn || !kv || !(flags & GWEN_CRYPT_TOKEN_KEYFLAGS_HASMODULUS) || !(flags & GWEN_CRYPT_TOKEN_KEYFLAGS_HASEXPONENT)))
res = 0;
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): id %ld %d %d m %d e %d -> %d.", __FUNCTION__, (long)id, kn, kv,
(flags & GWEN_CRYPT_TOKEN_KEYFLAGS_HASMODULUS) != 0, (flags & GWEN_CRYPT_TOKEN_KEYFLAGS_HASEXPONENT) != 0, res);
}
return (res == 1) ? 1 : 0;
}
#if 1
int8_t setKeyVersion(GWEN_CRYPT_TOKEN *ct, const GWEN_CRYPT_TOKEN_CONTEXT *ctx, const GWEN_CRYPT_TOKEN_KEYINFO *ki, char t, uint32_t kv)
{
int8_t ret = 0;
GWEN_CRYPT_TOKEN_KEYINFO *kin = NULL;
uint32_t kid = 0;
switch(t)
{
case 'V': kid = GWEN_Crypt_Token_Context_GetDecipherKeyId(ctx); break;
case 'S': kid = GWEN_Crypt_Token_Context_GetSignKeyId(ctx); break;
case 'A': kid = GWEN_Crypt_Token_Context_GetAuthSignKeyId(ctx); break;
default:
DBG_ERROR(AQHBCI_LOGDOMAIN, "type %c invalid.", t);
return -1;
}
kin = GWEN_Crypt_Token_KeyInfo_dup(ki);
if(kv > 999)
kv = 1;
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): key %ld '%c' set version %ld.", __FUNCTION__, (long)kid, t, (long)kv);
GWEN_Crypt_Token_KeyInfo_SetKeyVersion(kin, kv);
if(GWEN_Crypt_Token_SetKeyInfo(ct, kid, kin, 0))
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): GWEN_Crypt_Token_SetKeyInfo() failed.", __FUNCTION__);
ret = -1;
}
GWEN_Crypt_Token_KeyInfo_free(kin);
if(ret)
return ret;
if((ret == 0) && (ki = GWEN_Crypt_Token_GetKeyInfo(ct, kid, 0, 0)) == NULL)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): GWEN_Crypt_Token_GetKeyInfo() (%c) failed.", __FUNCTION__, t);
ret = -1;
}
if(ret)
return ret;
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): key '%c' version now %d.", __FUNCTION__, t, GWEN_Crypt_Token_KeyInfo_GetKeyVersion(ki));
return 0;
}
#endif
#define FJCK_CHMEDIA 1
#define FJCK_CHKEY 2
#define FJCK_CHPROFILE 4
#define FJCK_SRCFILE 8
#define FJCK_DSTFILE 16
#define FJCK_DSTFILE_EXISTS 32
void GWENHYWFAR_CB GWENHYWFAR_CB AH_Job_ChangeKeys_FreeData(void *bp, void *p);
int AH_Job_ChangeKeys_NextMsg(AH_JOB *j);
AH_JOB *AH_Job_ChangeKeys_new(AB_PROVIDER *pro, AB_USER *u, GWEN_DB_NODE *args, uint8_t *canceled)
{
int res = 0;
char fmtBuff[256];
AH_JOB *j = NULL;
AH_JOB_CHANGEKEYS *jd = NULL;
AB_USER *uTmp = NULL;
AH_HBCI *h = AH_Provider_GetHbci(pro);
uint16_t flags = FJCK_CHKEY | FJCK_CHMEDIA | FJCK_CHPROFILE;
AH_CRYPT_MODE cryptModeNew = AH_CryptMode_None;
int cryptTypeNew = -1;
int tokenCtxIdNew = -1;
const char *tt = NULL;
const char *tn = NULL;
char *ttn = NULL, *tnn = NULL;
const char *scmn = NULL;
GWEN_CRYPT_TOKEN *ct = NULL, *ctNew = NULL;
const GWEN_CRYPT_TOKEN_CONTEXT *ctx = NULL, *ctxNew = NULL;
const GWEN_CRYPT_TOKEN_KEYINFO *kiV = NULL, *kiS = NULL, *kiA = NULL, *kiVNew = NULL, *kiSNew = NULL, *kiANew = NULL;
GWEN_PLUGIN *plg = NULL;
GWEN_PLUGIN_MANAGER *pm = GWEN_PluginManager_FindPluginManager(GWEN_CRYPT_TOKEN_PLUGIN_TYPENAME);
const char *cmn = "?", *fm = "?", *fmn = "?";
assert(h);
//GWEN_DB_Dump(args, 0);
ttn = strdup(GWEN_DB_GetCharValue(args, "tokenType", 0, ""));
tnn = strdup(GWEN_DB_GetCharValue(args, "tokenName", 0, ""));
scmn = GWEN_DB_GetCharValue(args, "cryptMode", 0, "");
cryptTypeNew = GWEN_DB_GetIntValue(args, "cryptType", 0, -1);
tokenCtxIdNew = GWEN_DB_GetIntValue(args, "context", 0, -1);
if(scmn && *scmn)
{
if(!strcasecmp(scmn, "RDH"))
cryptModeNew = AH_CryptMode_Rdh;
else if(!strcasecmp(scmn, "RAH"))
cryptModeNew = AH_CryptMode_Rah;
}
tt = AH_User_GetTokenType(u);
tn = AH_User_GetTokenName(u);
if(!strcasecmp(tt, "ohbci"))
flags |= FJCK_SRCFILE;
if(!*ttn)
{
free(ttn);
ttn = NULL;
if(*tnn && !strchr(tnn, '/') && !strchr(tnn, '\\')) // assume thats a card number
{
size_t l = strlen(tnn);
size_t i = 0;
for(; i < l; i++)
{
if((tnn[i] < '0') || (tnn[i] > '9'))
break;
}
if(i == l)
{
ttn = strdup("card");
if(l < 10)
{
char *tmp = strdup("0000000000");
for(i = 0; i < l; i++)
tmp[9 - i] = tnn[(l - 1) - i];
free(tnn);
tnn = tmp;
}
}
}
}
if(ttn && !*ttn)
{
free(ttn);
ttn = NULL;
}
if(!ttn)
ttn = strdup(tt);
if(!strcasecmp(ttn, "file") || !strcasecmp(ttn, "ohbci"))
{
flags |= FJCK_DSTFILE;
free(ttn);
ttn = strdup("ohbci");
}
else if(!strstr(ttn, "card"))
res = onError(fmtStr(FB, "Ungültiger token-typ '%s'.", ttn), -1);
if(!*tnn)
{
free(tnn);
tnn = strdup(tn);
if(!strcasecmp(tt, "ohbci"))
flags |= FJCK_DSTFILE;
}
if(res == 0)
{
if(!access(tnn, F_OK))
flags |= FJCK_DSTFILE_EXISTS;
if(!strcasecmp(tt, ttn) && !strcmp(tn, tnn))
{
if(cryptModeNew == AH_CryptMode_None)
cryptModeNew = AH_User_GetCryptMode(u);
if(cryptTypeNew < 0)
cryptTypeNew = AH_User_GetRdhType(u);
}
if(cryptModeNew == AH_CryptMode_None)
res = onError("Crypt-mode muss angegeben werden.", -1);
if((res == 0) && (cryptTypeNew < 0))
res = onError("Crypt-typ muss angegeben werden.", -1);
}
if(tokenCtxIdNew < 0)
tokenCtxIdNew = 1;
fm = (flags & FJCK_SRCFILE) ? "Schlüsseldatei" : "Chipkarte";
fmn = (flags & FJCK_DSTFILE) ? "Schlüsseldatei" : "Chipkarte";
DBG_INFO(AQHBCI_LOGDOMAIN, "'%s' '%s' -> '%s' '%s', file %d exists %d'.", tt, tn, ttn, tnn, (flags & FJCK_DSTFILE) != 0, (flags & FJCK_DSTFILE_EXISTS) != 0);
if(res == 0)
{
if((((flags & FJCK_SRCFILE) != 1) == ((flags & FJCK_DSTFILE) != 1)) && !strcmp(tn, tnn))
res = onError("Schlüsseländerung ohne Medienänderung z.Zt. nicht unterstützt.", -1);
}
if(res == 0)
{
switch(cryptModeNew)
{
case AH_CryptMode_Rah: cmn = "RAH"; break;
case AH_CryptMode_Rdh: cmn = "RDH"; break;
default:
cmn = "unknown";
}
if(!strcasecmp(tt, ttn) && !strcmp(tn, tnn))
flags &= ~FJCK_CHMEDIA;
if((AH_User_GetCryptMode(u) == cryptModeNew) && (AH_User_GetRdhType(u) == cryptTypeNew))
flags &= ~FJCK_CHPROFILE;
DBG_INFO(AQHBCI_LOGDOMAIN, "'%s %d' -> '%s' '%s' '%s %d', change: m %d, k %d, p %d.", AH_CryptMode_toString(AH_User_GetCryptMode(u)), AH_User_GetRdhType(u),
ttn, tnn, AH_CryptMode_toString(cryptModeNew), cryptTypeNew, (flags & FJCK_CHMEDIA) != 0, (flags & FJCK_CHKEY) != 0, (flags & FJCK_CHPROFILE) != 0);
if(flags & FJCK_CHPROFILE)
{
res = -1;
switch(AH_User_GetCryptMode(u))
{
case AH_CryptMode_Rdh:
switch(cryptModeNew)
{
case AH_CryptMode_Rdh:
onError("Änderung des Schlüsselsprofils nach RDH nicht unterstützt.", -1);
break;
default:
if(!(flags & FJCK_SRCFILE) && !(flags & FJCK_DSTFILE) && (AH_User_GetRdhType(u) == 9) && (cryptTypeNew == 9))
res = 1;
else if((flags & FJCK_SRCFILE) && !(flags & FJCK_DSTFILE) && (AH_User_GetRdhType(u) == 10) && (cryptTypeNew == 9))
res = 1;
else if((flags & FJCK_SRCFILE) && (flags & FJCK_DSTFILE) && (AH_User_GetRdhType(u) == 10) && (cryptTypeNew == 10))
res = 1;
if(res == 1)
{
flags &= ~FJCK_CHKEY;
res = 0;
}
else
{
if(flags & FJCK_SRCFILE)
{
switch(AH_User_GetRdhType(u))
{
case 1:
case 2:
if(!(flags & FJCK_DSTFILE) && (cryptTypeNew == 9))
res = 0;
if((flags & FJCK_DSTFILE) && (cryptTypeNew == 10))
res = 0;
break;
default:;
}
}
else
{
switch(AH_User_GetRdhType(u))
{
case 1:
case 5:
if(!(flags & FJCK_DSTFILE) && (cryptTypeNew == 9))
res = 0;
break;
default:;
}
}
if(res)
onError(fmtStr(FB, "Änderung des Schlüsselsprofils von %s RDH-%d nach %s RAH-%d nicht unterstützt.",
fm, AH_User_GetRdhType(u), fmn, cryptTypeNew), -1);
}
}
break;
default:
onError("Änderung des Sicherheitsprofils nur von RDH aus unterstützt.", -1);
}
}
if(res)
*canceled = 2;
}
if(res == 0)
{
// keyinfo current token
if(getKeyInfo(h, AH_User_GetTokenType(u), AH_User_GetTokenName(u), AH_User_GetTokenContextId(u), &ct, &ctx, &kiV, &kiS, &kiA)
|| !ct || !ctx || !kiV || !kiS || !kiA)
{
DBG_INFO(AQHBCI_LOGDOMAIN, "getKeyInfo() ct %p, ctx %p, ki %p %p %p.", ct, ctx, kiV, kiS, kiA);
if(!ct || !ctx)
res = onError("Could not get token.", -1);
else
res = onError("Sicherheitsmedium für diesen Vorgang nicht geeignet.", -1);
}
}
if((res == 0) && (flags & FJCK_CHMEDIA))
{
char *tokenNew = NULL;
if(!strcmp(ttn, "card"))
{
GWEN_BUFFER *ctn = GWEN_Buffer_new(0, 64, 0, 1);
GWEN_BUFFER *cmn = GWEN_Buffer_new(0, 64, 0, 1);
for(; res == 0;)
{
res = AB_Banking_CheckCryptToken(AB_Provider_GetBanking(pro), GWEN_Crypt_Token_Device_Card, ctn, cmn);
DBG_INFO(AQHBCI_LOGDOMAIN, "card: '%s' '%s'.", GWEN_Buffer_GetStart(ctn), GWEN_Buffer_GetStart(cmn));
if(res)
res = onError("AB_Banking_CheckCryptToken() failed.", -1);
else
{
if(tokenNew)
free(tokenNew);
tokenNew = strdup(GWEN_Buffer_GetStart(ctn));
if(!strcmp(tnn, GWEN_Buffer_GetStart(cmn)))
break;
if(GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: insert card"),
fmtStr(FB, "Chipkarte '%s' wird benötigt.", tnn), I18N("Abort"), I18N("OK"), NULL, 0) != 2)
res = -2;
}
}
GWEN_Buffer_free(ctn);
GWEN_Buffer_free(cmn);
if(tokenNew)
{
free(ttn);
ttn = tokenNew;
tokenNew = NULL;
}
}
if(tokenNew)
free(tokenNew);
if(res == 0)
plg = GWEN_PluginManager_GetPlugin(pm, ttn);
if(!plg && (res == 0))
res = onError(fmtStr(FB, "Could not get plugin for new tokentype '%s'.", ttn), -1);
if(plg && (flags & FJCK_DSTFILE))
{
// diff. context?
if((flags & FJCK_SRCFILE) && !strcmp(tn, tnn))
res = onError(fmtStr(FB, "Die alte und neue Schlüsseldatei darf nicht identisch sein."), -1);
else
{
uint8_t del = 1;
tokenCtxIdNew = 1;
if(flags & FJCK_DSTFILE_EXISTS)
{
del = 0;
res = GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
fmtStr(FB, "Die Schlüsseldatei '%s' existiert bereits.", tnn), I18N("Abort"), I18N("Use"), I18N("Delete"), 0);
if(res == 1)
res = -1;
else if(res == 2) // use
{
res = 0;
//flags &= ~FJCK_CHKEY;
if(getKeyInfo(h, ttn, tnn, tokenCtxIdNew, &ctNew, &ctxNew, &kiVNew, &kiSNew, &kiANew)
|| !ctNew || !ctxNew || !kiVNew || !kiSNew || !kiANew)
res = onError("Could not get token for new keyfile.", -1);
}
else if(GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
fmtStr(FB, "Schlüsseldatei '%s' wirklich löschen?", tnn), I18N("Abort"), I18N("Delete"), NULL, 0) != 2)
res = -1;
else
{
res = 0;
del = 1;
}
if(res)
{
res = onError("Canceled.", -1);
*canceled = 1;
}
else if(del)
unlink(tnn);
}
if((res == 0) && del)
{
if(GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
fmtStr(FB, "Schlüsseldatei '%s' wird erzeugt.", tnn), I18N("Abort"), I18N("OK"), NULL, 0) != 2)
{
res = onError("Canceled.", -1);
*canceled = 1;
}
if(res == 0)
{
ctNew = GWEN_Crypt_Token_Plugin_CreateToken(plg, tnn);
if(!ctNew)
res = onError(fmtStr(FB, "Could not create crypt token '%s'.", tnn), -1);
else if(GWEN_Crypt_Token_Create(ctNew, 0) < 0)
res = onError(fmtStr(FB, "Could not create keyfile '%s'.", GWEN_Crypt_Token_GetTokenName(ctNew)), -1);
else if(GWEN_Crypt_Token_Close(ctNew, 0, 0))
res = onError("Could not close token.", -1);
}
}
}
}
// keyinfo dest. token
if(res == 0)
{
if(getKeyInfo(h, ttn, tnn, tokenCtxIdNew, &ctNew, &ctxNew, &kiVNew, &kiSNew, &kiANew)
|| !ctNew || !ctxNew || !kiVNew || !kiSNew || !kiANew)
{
DBG_NOTICE(AQHBCI_LOGDOMAIN, "getKeyInfo() ct %p, ctx %p, ki %p %p %p.", ct, ctx, kiV, kiS, kiA);
if(!ct || !ctx)
res = onError("Could not get token.", -1);
else
res = onError("Sicherheitsmedium für diesen Vorgang nicht geeignet.", -1);
}
}
if((res == 0) && !(flags & FJCK_DSTFILE))
{
int tnV = GWEN_Crypt_Token_KeyInfo_GetKeyNumber(kiVNew);
int tnS = GWEN_Crypt_Token_KeyInfo_GetKeyNumber(kiSNew);
if((cryptTypeNew != tnV) || (cryptTypeNew != tnS))
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "rdh-type %d, card %d/%d..", cryptTypeNew, tnV, tnS);
res = onError("Ziel-Sicherheitsmedium für diesen Vorgang nicht geeignet.", -1);
}
}
}
#if 1
if(res == 0)
{
// how get key-pair from token?
if(!(flags & FJCK_CHKEY) && (flags & FJCK_CHMEDIA))
res = onError("Sicherheitsprofilwechsel ohne Sicherheitsmedienwechsel nicht implementiert.", -1);
}
#endif
if(res == 0)
{
if(flags & FJCK_CHMEDIA)
{
char *cm = strdup(AH_CryptMode_toString(AH_User_GetCryptMode(u)));
const char *m = fmtStr(FB, "Wechsel des Sicherheitsmediums von\n %s '%s', %s-%d\nnach\n %s '%s', %s-%d\ndurchführen?",
fm, tn, strUpper(cm), AH_User_GetRdhType(u), fmn, tnn, cmn, cryptTypeNew);
free(cm);
if(GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
m, I18N("Abort"), I18N("OK"), NULL, 0) != 2)
{
res = -1;
*canceled = 1;
}
}
}
if(res == 0)
{
uTmp = AB_Provider_CreateUserObject(pro);
AH_User_SetCryptMode(uTmp, cryptModeNew);
AH_User_SetRdhType(uTmp, cryptTypeNew);
AH_User_SetTokenType(uTmp, ttn);
AH_User_SetTokenName(uTmp, tnn);
AH_User_SetTokenContextId(uTmp, tokenCtxIdNew);
AB_User_SetBankCode(uTmp, AB_User_GetBankCode(u));
AH_User_SetHbciVersion(uTmp, AH_User_GetHbciVersion(u));
AH_User_SetServerUrl(uTmp, AH_User_GetServerUrl(u));
DBG_NOTICE(AQHBCI_LOGDOMAIN, "chng k %d p %d m %d, token: open %d ctx %d knr dst %d %d %d.",
(flags & FJCK_CHKEY) != 0, (flags & FJCK_CHPROFILE) != 0, (flags & FJCK_CHMEDIA) != 0, GWEN_Crypt_Token_IsOpen(ctNew), tokenCtxIdNew,
kiVNew ? GWEN_Crypt_Token_KeyInfo_GetKeyNumber(kiVNew) : - 1, kiSNew ? GWEN_Crypt_Token_KeyInfo_GetKeyNumber(kiSNew) : -1, kiANew ? GWEN_Crypt_Token_KeyInfo_GetKeyNumber(kiANew) : -1);
}
if(res == 0)
{
j = AH_Job_new((flags & FJCK_DSTFILE) ? "JobChangeKeys" : "JobChangeKeysA", pro, u, NULL, 0);
DBG_INFO(AQHBCI_LOGDOMAIN, "%s(): j %p u %p '%s'.", __FUNCTION__, j, u, j ? AH_Job_GetCode(j) : "-");
if(!j)
res = onError("AH_Job_new() failed.", -1);
}
if(res == 0)
{
GWEN_NEW_OBJECT(AH_JOB_CHANGEKEYS, jd);
GWEN_INHERIT_SETDATA(AH_JOB, AH_JOB_CHANGEKEYS, j, jd, AH_Job_ChangeKeys_FreeData);
AH_Job_SetNextMsgFn(j, AH_Job_ChangeKeys_NextMsg);
args = AH_Job_GetArguments(j);
assert(args);
}
if(res == 0)
{
char *cm = strdup(AH_CryptMode_toString(cryptModeNew));
strUpper(cm);
for(uint8_t i = 0; i < 3; i++)
{
const char *kt = "?";
GWEN_DB_NODE *db = NULL;
if(i < 2)
{
switch(i)
{
case 0: kt = "V"; db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "getcryptKey"); break;
case 1: kt = "S"; db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "getsignKey"); break;
}
// HKISA
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "secProfile/code", cm);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "secProfile/version", cryptTypeNew);
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/userid", AH_User_GetPeerId(u));
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/keyType", kt);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/keynum", 999);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/keyversion", 999);
}
switch(i)
{
case 0: kt = "V"; db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "setcryptKey"); break;
case 1: kt = "S"; db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "setsignKey"); break;
case 2: kt = "D"; db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "setauthKey"); break;
}
// HKSAK
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "secProfile/code", cm);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "secProfile/version", cryptTypeNew);
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/userid", AH_User_GetPeerId(u));
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/keyType", kt);
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "keyName/keyType", kt);
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "keyName/userid", AH_User_GetPeerId(u));
}
free(cm);
}
if(res)
{
if(j)
AH_Job_free(j);
j = NULL;
if(res == -2)
*canceled = 2;
}
if(jd)
{
jd->flags = flags;
jd->canceled = canceled;
jd->pro = pro;
jd->u = u;
jd->uTmp = uTmp;
jd->fm = fmn;
jd->tt = ttn;
jd->tn = tnn;
jd->kvVCurr = kiV ? GWEN_Crypt_Token_KeyInfo_GetKeyVersion(kiV) : 0;
jd->kvSCurr = kiS ? GWEN_Crypt_Token_KeyInfo_GetKeyVersion(kiS) : 0;
jd->kvACurr = kiA ? GWEN_Crypt_Token_KeyInfo_GetKeyVersion(kiA) : 0;
jd->ct = ctNew;
jd->ctx = ctxNew;
jd->tokenCtxId = tokenCtxIdNew;
jd->kiV = kiVNew;
jd->kiS = kiSNew;
jd->kiA = kiANew;
jd->resp = -1;
jd->emsg = NULL;
}
if(ctNew)
GWEN_Crypt_Token_Close(ctNew, 0, 0);
if(ct)
GWEN_Crypt_Token_Close(ct, 0, 0);
return j;
}
int onServerKeysImported(AH_JOB_CHANGEKEYS *jd)
{
// serverkeys imported (knowing server-keys length is necessary for some key-types when created)
// create keys if required
char fmtBuff[256];
AH_HBCI *h = AH_Provider_GetHbci(jd->pro);
int res = 0;
const char *m = NULL;
const char *btn1 = NULL, *btn2 = NULL, *btn3 = NULL;
uint8_t ok = 0;
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): flags 0x%04X.", __FUNCTION__, jd->flags);
if(jd->flags & FJCK_CHKEY)
{
//if(!jd->kiV || !GWEN_Crypt_Token_KeyInfo_GetKeyNumber(jd->kiV) || !jd->kiS || !GWEN_Crypt_Token_KeyInfo_GetKeyNumber(jd->kiS))
if(!tokenHasKeys(jd->ct, jd->ctx))
{
m = fmtStr(FB, "Neue Schlüssel werden auf %s '%s' erzeugt.", jd->fm, jd->tn);
btn1 = "Abort";
btn2 = "OK";
ok = 2;
}
else
{
#if 0
// TODO check keys are compatible with cryptmode
// if so, ...
{
m = fmtStr(FB, "Auf %s '%s' sind Schlüssel vorhanden,\nsollen dennoch neue Schlüssel erzeugt werden?", fmn, tnn);
btn1 = "Abort";
btn2 = "No";
btn3 = "Yes";
ok = 3;
}
else
{
m = fmtStr(FB, "Auf %s '%s' vorhandene Schlüssel können nicht verwendet werden,\nneue Schlüssel werden erzeugt.", fmn, tnn);
btn1 = "Abort";
btn2 = "OK";
ok = 2;
}
#else
m = fmtStr(FB, "Auf %s '%s' sind Schlüssel vorhanden die verwendet werden können,\n"
"wenn sie zum gewählten Verschlüsselungsverfahren passen.\n"
"Sollen neue Schlüssel erzeugt werden?", jd->fm, jd->tn);
btn1 = "Abort";
btn2 = "No";
btn3 = "Yes";
ok = 3;
#endif
}
res = GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
m, I18N(btn1), I18N(btn2), btn3 ? I18N(btn3) : NULL, 0);
if(res == 1)
{
res = -1;
*jd->canceled = 1;
}
else
{
if(res == ok)
{
res = 0;
DBG_INFO(AQHBCI_LOGDOMAIN, "creating keys...");
res = AH_Provider_CreateKeys(jd->pro, jd->uTmp, 1);
if(res)
res = onError(fmtStr(FB, "Could not create keys (%d).", res), -1);
DBG_INFO(AQHBCI_LOGDOMAIN, "creating keys done.");
}
else
res = 0;
}
}
else
res = -1;
if((res == 0) && (getKeyInfo(h, jd->tt, jd->tn, jd->tokenCtxId, &jd->ct, &jd->ctx, &jd->kiV, &jd->kiS, &jd->kiA)
|| !jd->ct || !jd->ctx || !jd->kiV || !jd->kiS || !jd->kiA))
res = onError("Could not get key-info.", -1);
if(res == 0)
{
#if 1
if(!(jd->flags & FJCK_CHPROFILE))
{
// set keyversion from current token + 1 on dest.-token
uint32_t kvV = jd->kvVCurr ? (jd->kvVCurr + 1) : 0;
uint32_t kvS = jd->kvSCurr ? (jd->kvSCurr + 1) : 0;
uint32_t kvA = jd->kvACurr ? (jd->kvACurr + 1) : 0;
DBG_NOTICE(AQHBCI_LOGDOMAIN, "set keyversions %ld -> %ld, %ld -> %ld, %ld -> %ld.",
(long)jd->kvVCurr, (long)kvV, (long)jd->kvSCurr, (long)kvS, (long)jd->kvACurr, (long)kvA);
if(kvV)
setKeyVersion((GWEN_CRYPT_TOKEN*)jd->ct, jd->ctx, jd->kiV, 'V', kvV);
if(kvS)
setKeyVersion((GWEN_CRYPT_TOKEN*)jd->ct, jd->ctx, jd->kiS, 'S', kvS);
if(!(jd->flags & FJCK_DSTFILE) && kvA)
setKeyVersion((GWEN_CRYPT_TOKEN*)jd->ct, jd->ctx, jd->kiA, 'A', kvA);
}
#endif
if(jd->flags & FJCK_CHKEY)
{
if(!jd->kiS || !GWEN_Crypt_Token_KeyInfo_GetKeyNumber(jd->kiS))
{
DBG_INFO(AQHBCI_LOGDOMAIN, "Kein Signierschlüssel.");
res = onError("Kein Signierschlüssel auf dem Ziel-medium gefunden.", -1);
}
else
{
int sc = GWEN_Crypt_Token_KeyInfo_GetSignCounter(jd->kiS);
DBG_INFO(AQHBCI_LOGDOMAIN, "%s(): sig counter %d.", __FUNCTION__, sc);
if(sc > 1)
{
if(!(jd->flags & FJCK_DSTFILE))
res = onError("Der Sequenzzähler kann nicht zurückgesetzt werden.", -1);
else
{
res = GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
"Der Sequenzzähler wird zurückgesetzt.", I18N("Abort"), I18N("OK"), NULL, 0);
if(res != 2)
res = -1;
else
res = 0;
}
if(res == 0)
{
DBG_INFO(AQHBCI_LOGDOMAIN, "%s(): reset sig counter.", __FUNCTION__);
GWEN_Crypt_Token_KeyInfo_SetSignCounter((GWEN_CRYPT_TOKEN_KEYINFO*)jd->kiS, 1);
}
}
}
}
}
if(res == 0)
{
if(getKeyInfo(h, jd->tt, jd->tn, jd->tokenCtxId, &jd->ct, &jd->ctx, &jd->kiV, &jd->kiS, &jd->kiA)
|| !jd->ct || !jd->ctx || !jd->kiV || !jd->kiS || !jd->kiA)
res = onError("Could not get key-info.", -1);
}
if((res == 0) && !jd->ctx)
res = onError("Missing new ctx.", -1);
return res;
}
#define RSP_NOSRVRSP 1
#define RSP_WARN 2
#define RSP_ERR 3
int8_t parseResponse(AH_JOB *j)
{
int8_t res = 0;
int rc = 0;
uint8_t gotResp = 0;
AH_JOB_CHANGEKEYS *jd = GWEN_INHERIT_GETDATA(AH_JOB, AH_JOB_CHANGEKEYS, j);
GWEN_DB_NODE *n = AH_Job_GetResponses(j);
if(AH_Job_GetStatus(j) != AH_JobStatusAnswered)
rc = -1;
assert(n);
jd->emsg = GWEN_Buffer_new(NULL, 2048, 0, 0);
n = GWEN_DB_GetFirstGroup(n);
while(n)
{
//GWEN_DB_Dump(n, 0);
if(!strcmp(GWEN_DB_GroupName(n), "SegResult"))
{
int mn = GWEN_DB_GetIntValue(n, "security/msgnum", 0, -1);
if(mn == 2)
{
gotResp = 1;
if((rc >= 0) && (rc < 9000))
{
rc = GWEN_DB_GetIntValue(n, "data/SegResult/result/resultcode", 0, -1);
if(rc == 3250)
{
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): response %d tells us: no HKEND.", __FUNCTION__, rc);
res = 1;
rc = 0;
}
else
{
GWEN_Buffer_AppendString(jd->emsg, GWEN_DB_GetCharValue(n, "data/SegResult/result/text", 0, "?"));
GWEN_Buffer_AppendString(jd->emsg, "\n");
}
}
DBG_NOTICE(AQHBCI_LOGDOMAIN, "result %d.", rc);
DBG_NOTICE(AQHBCI_LOGDOMAIN, "result '%s'.", GWEN_Buffer_GetStart(jd->emsg));
}
else
{
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): #%d result %d '%s'.", __FUNCTION__,
GWEN_DB_GetIntValue(n, "security/msgnum", 0, -1),
GWEN_DB_GetIntValue(n, "data/SegResult/result/resultcode", 0, -1),
GWEN_DB_GetCharValue(n, "data/SegResult/result/text", 0, "?"));
if(GWEN_DB_GetIntValue(n, "data/SegResult/result/resultcode", 0, -1) >= 9000)
{
rc = GWEN_DB_GetIntValue(n, "data/SegResult/result/resultcode", 0, -1);
GWEN_Buffer_AppendString(jd->emsg, GWEN_DB_GetCharValue(n, "data/SegResult/result/text", 0, "?"));
GWEN_Buffer_AppendString(jd->emsg, "\n");
}
}
}
n = GWEN_DB_GetNextGroup(n);
}
if(!gotResp)
jd->resp = RSP_NOSRVRSP;
else
jd->resp = (rc < 3000) ? 0 : (rc < 9000) ? RSP_WARN : RSP_ERR;
return res;
}
void GWENHYWFAR_CB GWENHYWFAR_CB AH_Job_ChangeKeys_FreeData(void *bp, void *p)
{
AH_JOB_CHANGEKEYS *jd = (AH_JOB_CHANGEKEYS*)p;
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): %p uTmp %p.", __FUNCTION__, jd, jd->uTmp);
if(jd->uTmp)
AB_User_free(jd->uTmp);
if(jd->tt)
free(jd->tt);
if(jd->tn)
free(jd->tn);
if(jd->emsg)
GWEN_Buffer_free(jd->emsg);
GWEN_FREE_OBJECT(jd);
}
int AH_Job_ChangeKeys_NextMsg(AH_JOB *j)
{
int rv = 0;
int mn = -1;
unsigned int jmn = 0;
GWEN_DB_NODE *dbr = NULL;
AH_JOB_CHANGEKEYS *jd;
assert(j);
jmn = AH_Job_GetMsgNum(j);
dbr = AH_Job_GetResponses(j);
dbr = GWEN_DB_GetFirstGroup(dbr);
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): jmn %d.", __FUNCTION__, jmn);
while(dbr)
{
//GWEN_DB_Dump(dbr, 0);
rv = AH_Job_CheckEncryption(j, dbr);
if(rv)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): AH_Job_CheckEncryption() failed (%d).", __FUNCTION__, rv);
return -1;
}
rv = AH_Job_CheckSignature(j, dbr);
if(rv)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): AH_Job_CheckSignature() failed (%d).", __FUNCTION__, rv);
return -1;
}
if(!strcasecmp(GWEN_DB_GroupName(dbr), "MsgTail"))
{
mn = GWEN_DB_GetIntValue(dbr, "security/msgnum", 0, -1);
if(mn < 0)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s: find msgnum failed.", __FUNCTION__);
}
else if((mn == 1) && (jmn == mn))
{
const GWEN_CRYPT_KEY *bk = NULL;
GWEN_CRYPT_KEY *bkCurrV = NULL, *bkCurrS = NULL;
jd = GWEN_INHERIT_GETDATA(AH_JOB, AH_JOB_CHANGEKEYS, j);
assert(jd);
// get actual serverkeys to restore later
bk = AH_User_GetBankPubCryptKey(jd->u);
if(bk)
bkCurrV = GWEN_Crypt_KeyRsa_dup(bk);
bk = AH_User_GetBankPubSignKey(jd->u);
if(bk)
bkCurrS = GWEN_Crypt_KeyRsa_dup(bk);
rv = AH_Job_CommitSystemData(j, 0);
if(rv != 0)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): AH_Job_CommitSystemData() failed(%d).", __FUNCTION__, rv);
}
else if(!GWEN_Crypt_Token_IsOpen(jd->ct) && (GWEN_Crypt_Token_Open(jd->ct, 0, 0) < 0))
rv = onError("GWEN_Crypt_Token_Open() failed.", -1);
else
{
GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Info, I18N("Serverkeys imported."));
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): serverkeys should be imported now.", __FUNCTION__);
// some cryptmodes need length of serverkeys
// AH_Provider_CreateKeys() reads the length from user-token,
// which is the temporary user with the new token,
// so store server-keys from actual user (the now imported) on the new token
//DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): ctx %p.", __FUNCTION__, jd->ctx);
jd->ctx = GWEN_Crypt_Token_GetContext(jd->ct, jd->tokenCtxId, 0);
//DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): -> ctx %p.", __FUNCTION__, jd->ctx);
for(uint8_t i = 0; (rv == 0) && (i < 2); i++)
{
const GWEN_CRYPT_TOKEN_KEYINFO *tmp = NULL;
uint8_t *m = NULL, *e = NULL;
uint32_t ml = 0, el = 0;
uint32_t id = 0;
bk = NULL;
switch(i)
{
case 0:
bk = AH_User_GetBankPubCryptKey(jd->u);
id = GWEN_Crypt_Token_Context_GetEncipherKeyId(jd->ctx);
AH_User_SetBankPubCryptKey(jd->uTmp, (GWEN_CRYPT_KEY*)bk);
break;
case 1:
bk = AH_User_GetBankPubSignKey(jd->u);
id = GWEN_Crypt_Token_Context_GetVerifyKeyId(jd->ctx);
AH_User_SetBankPubSignKey(jd->uTmp, (GWEN_CRYPT_KEY*)bk);
break;
}
if(!bk)
{
if(i == 0)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): get bankkey failed.", __FUNCTION__);
rv = -1;
}
else
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): bank has no signkey.", __FUNCTION__);
continue;
}
ml = GWEN_Crypt_Key_GetKeySize(bk);
el = 3;
if(ml)
{
m = malloc(ml);
e = malloc(el);
GWEN_Crypt_KeyRsa_GetModulus(bk, m, &ml);
GWEN_Crypt_KeyRsa_GetExponent(bk, e, &el);
}
tmp = GWEN_Crypt_Token_GetKeyInfo(jd->ct, id, 0, 0);
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): k %ld m %ld %p e %ld %p.", __FUNCTION__, (long)id, (long)ml, m, (long)el, e);
if(!tmp)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): damn, get keyinfo '%c' failed.", __FUNCTION__, (i == 0) ? 'V' : 'S');
rv = onError("GWEN_Crypt_Token_GetKeyInfo() failed.", -1);
}
if(rv == 0)
{
GWEN_CRYPT_TOKEN_KEYINFO *ki = GWEN_Crypt_Token_KeyInfo_dup(tmp);
uint32_t flags = GWEN_Crypt_Token_KeyInfo_GetFlags(ki);
GWEN_Crypt_Token_KeyInfo_SetFlags(ki, flags | GWEN_CRYPT_TOKEN_KEYFLAGS_HASMODULUS | GWEN_CRYPT_TOKEN_KEYFLAGS_HASEXPONENT);
GWEN_Crypt_Token_KeyInfo_SetModulus(ki, m, ml);
GWEN_Crypt_Token_KeyInfo_SetExponent(ki, e, el);
GWEN_Crypt_Token_KeyInfo_SetKeySize(ki, ml);
GWEN_Crypt_Token_KeyInfo_SetKeyNumber(ki, GWEN_Crypt_Key_GetKeyNumber(bk));
GWEN_Crypt_Token_KeyInfo_SetKeyVersion(ki, GWEN_Crypt_Key_GetKeyVersion(bk));
if(GWEN_Crypt_Token_SetKeyInfo(jd->ct, id, ki, 0))
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): GWEN_Crypt_Token_SetKeyInfo() failed.", __FUNCTION__);
rv = -1;
}
else
ki = NULL;
if(ki)
GWEN_Crypt_Token_KeyInfo_free(ki);
}
if(m)
free(m);
if(e)
free(e);
}
if(rv == 0)
{
rv = onServerKeysImported(jd);
if(rv != 0)
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): onServerKeysImported() failed.", __FUNCTION__);
}
// serverkeys set in job_commit() must restored
if(bkCurrV)
{
AH_User_SetBankPubCryptKey(jd->u, bkCurrV);
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): serverkey 'V' restored.", __FUNCTION__);
GWEN_Crypt_Key_free(bkCurrV);
}
if(bkCurrS)
{
AH_User_SetBankPubSignKey(jd->u, bkCurrS);
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): serverkey 'S' restored.", __FUNCTION__);
GWEN_Crypt_Key_free(bkCurrS);
}
if(rv == 0)
{
// update segment-data
GWEN_DB_NODE *args = AH_Job_GetArguments(j);
assert(args);
for(uint8_t i = 0; (rv == 0) && (i < 3); i++)
{
GWEN_DB_NODE *db = NULL;
const GWEN_CRYPT_TOKEN_KEYINFO *ki = NULL;
const uint8_t *kd = NULL;
uint32_t kdsz = 0;
const char *kt = "?";
int kn = 0, kv = 0;
switch(i)
{
case 0: kt = "V"; ki = jd->kiV; db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "setcryptKey"); break;
case 1: kt = "S"; ki = jd->kiS; db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "setsignKey"); break;
case 2: kt = "D"; ki = jd->kiA; db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "setauthKey"); break;
}
if(!ki)
{
if(i < 2)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): get keyinfo '%s' failed.", __FUNCTION__, kt);
rv = -1;
}
else
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): token has no authkey.", __FUNCTION__);
continue;
}
kd = GWEN_Crypt_Token_KeyInfo_GetModulusData(ki);
kdsz = GWEN_Crypt_Token_KeyInfo_GetModulusLen(ki);
if(!kd || !kdsz)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "No modulus in '%s' key.", kt);
rv = -1;
break;
}
GWEN_DB_SetBinValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/modulus", kd, kdsz);
kd = GWEN_Crypt_Token_KeyInfo_GetExponentData(ki);
kdsz = GWEN_Crypt_Token_KeyInfo_GetExponentLen(ki);
if(!kd || !kdsz)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "No exponent in '%s' key.", kt);
rv = -1;
break;
}
GWEN_DB_SetBinValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/exponent", kd, kdsz);
kd = GWEN_Crypt_Token_KeyInfo_GetCertificateData(ki);
kdsz = GWEN_Crypt_Token_KeyInfo_GetCertificateLen(ki);
if(kd && kdsz)
{
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "cert/type", GWEN_Crypt_Token_KeyInfo_GetCertType(ki));
GWEN_DB_SetBinValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "cert/cert", kd, kdsz);
}
else
DBG_NOTICE(AQHBCI_LOGDOMAIN, "No cert for '%s' on token.", kt);
kn = GWEN_Crypt_Token_KeyInfo_GetKeyNumber(ki);
kv = GWEN_Crypt_Token_KeyInfo_GetKeyVersion(ki);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/keynum", kn);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/keyversion", kv);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "keyName/keynum", kn);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "keyName/keyversion", kv);
}
}
}
}
else if((mn == 2) && (jmn == mn))
{
int8_t resp = parseResponse(j);
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s: resp %d, %s HKEND.", __FUNCTION__, resp, (resp == 1) ? "no" : "next");
if(resp == 1) // since 5.99.25 no chance to prevent HKEND :-(
return 0;
}
}
dbr = GWEN_DB_GetNextGroup(dbr);
}
return (rv == 0) ? 1 : -1;
}
int AH_Job_ChangeKeys_finish(AB_PROVIDER *pro, AH_JOB *job, int res)
{
AH_JOB_CHANGEKEYS *jd = NULL;
AB_USER *u = NULL;
AB_USER *uTmp = NULL;
if(!job)
return res;
jd = GWEN_INHERIT_GETDATA(AH_JOB, AH_JOB_CHANGEKEYS, job);
if(*jd->canceled)
{
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): user canceled.", __FUNCTION__);
jd->resp = -1;
}
u = jd->u;
uTmp = jd->uTmp;
res = -1;
if(jd->resp >= 0)
{
char fmtBuff[1024];
const char *m = NULL;
const char *btn1 = I18N("Abort");
const char *btn2 = I18N("Finish");
if(jd->resp == RSP_NOSRVRSP)
{
GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: Error"),
"Der Bankserver hat keine Antwort zur Schlüsseländerung gesendet.", I18N("OK"), NULL, NULL, 0);
res = -1;
}
else
{
if((jd->resp == RSP_WARN) || (jd->resp == RSP_ERR))
{
m = strdup(fmtStr(FB, "Der Bankserver meldet %s:\n\n'%s'\n\n"
"Es ist möglich, dass der neue Schlüssel dennoch angenommenn wurde.\n"
"Neue Schlüssel / neues Medium übernehmen?", (jd->resp == RSP_ERR) ? "Fehler" : "Warnungen",
GWEN_Buffer_GetStart(jd->emsg)));
btn1 = I18N("No");
btn2 = fmtStr(FB, "%s, %s", I18N("Yes"), I18N("finish"));
}
else
{
m = strdup(fmtStr(FB, "Die Übermittlung der Schlüssel ergab keinen Fehler,\n"
"aus den Meldungen des Bankservers sollte eine Übernahme ersichtlich sein:\n\n%s\nNeue Schlüssel / neues Medium\n"
"wird übernommen.", GWEN_Buffer_GetStart(jd->emsg)));
}
if(GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
m, btn1, btn2, NULL, 0) == 2)
res = 0;
}
if(m)
free((char*)m);
}
DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): %d/%d %p %p.", __FUNCTION__, jd->resp, res, u, uTmp);
if(uTmp)
{
DBG_INFO(AQHBCI_LOGDOMAIN, "%s: tt '%s' tn '%s' rdh %d cm %d ctx-id %d.", __FUNCTION__,
AH_User_GetTokenType(uTmp), AH_User_GetTokenName(uTmp), AH_User_GetRdhType(uTmp),
AH_User_GetCryptMode(uTmp), AH_User_GetTokenContextId(uTmp));
if(res == 0)
{
if(AB_Provider_BeginExclUseUser(pro, u))
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): AB_Provider_BeginExclUseUser() failed.", __FUNCTION__);
res = -1;
}
else
{
AH_User_SetBankPubCryptKey(u, AH_User_GetBankPubCryptKey(uTmp));
AH_User_SetBankPubSignKey(u, AH_User_GetBankPubSignKey(uTmp));
AH_User_SetTokenType(u, AH_User_GetTokenType(uTmp));
AH_User_SetTokenName(u, AH_User_GetTokenName(uTmp));
AH_User_SetRdhType(u, AH_User_GetRdhType(uTmp));
AH_User_SetCryptMode(u, AH_User_GetCryptMode(uTmp));
AH_User_SetTokenContextId(u, AH_User_GetTokenContextId(uTmp));
if(AB_Provider_EndExclUseUser(pro, u, 0))
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): AB_Provider_EndExclUseUser() failed.", __FUNCTION__);
res = -1;
}
}
}
AB_Provider_DeleteUser(pro, AB_User_GetUniqueId(uTmp));
}
return res;
}
src/libs/plugins/backends/aqhbci/admjobs/jobchangekeys.xml
<!--
/***************************************************************************
***************************************************************************
* Please see toplevel file COPYING for license details *
***************************************************************************/
-->
<SEGs>
<SEGdef id="ChangeKeys"
code="HKSAK"
version="3"
pversion="300"
delimiter="+"
terminator="'">
<GROUP type="SegHead" name="head" />
<ELEM name="context" type="num" maxsize="1" />
<ELEM name="fntyp" type="num" maxsize="3" />
<GROUP type="SecProfile" name="secProfile" />
<GROUP name="keyName" type="signkeyname" />
<GROUP name="key" type="signkey" trustlevel="3" />
<GROUP name="cert" type="cert" minnum="0" />
<VALUES>
<VALUE path="head/code">%code</VALUE>
<VALUE path="head/version">%version</VALUE>
<VALUE path="context">2</VALUE>
<VALUE path="fntyp">112</VALUE>
</VALUES>
</SEGdef>
</SEGs>
<JOBs>
<JOBdef id="JobChangeKeys"
version="4"
dlg="1"
needbpd="0"
>
<MESSAGE name="open" >
<SEG type="Ident" name="ident" />
<SEG type="Prepare" name="prepare" version="3" />
<SEG type="GetKey" version="3" name="getcryptKey" />
<SEG type="GetKey" version="3" name="getsignKey" />
</MESSAGE>
<MESSAGE>
<SEG type="ChangeKeys" version="3" name="setcryptKey" />
<SEG type="ChangeKeys" version="3" name="setsignKey" />
</MESSAGE>
<MESSAGE name="close" >
<SEG type="DialogEnd" />
</MESSAGE>
</JOBdef>
<JOBdef id="JobChangeKeysA"
version="4"
dlg="1"
needbpd="0"
>
<MESSAGE name="open" >
<SEG type="Ident" name="ident" />
<SEG type="Prepare" name="prepare" version="3" />
<SEG type="GetKey" version="3" name="getcryptKey" />
<SEG type="GetKey" version="3" name="getsignKey" />
</MESSAGE>
<MESSAGE>
<SEG type="ChangeKeys" version="3" name="setcryptKey" />
<SEG type="ChangeKeys" version="3" name="setsignKey" />
<SEG type="ChangeKeys" version="3" name="setauthKey" />
</MESSAGE>
<MESSAGE name="close" >
<SEG type="DialogEnd" />
</MESSAGE>
</JOBdef>
</JOBs>
src/libs/plugins/backends/aqhbci/admjobs/jobchangekeys_l.h
/***************************************************************************
***************************************************************************
* Please see toplevel file COPYING for license details *
***************************************************************************/
#ifndef AH_JOBCHANGEKEYS_L_H
#define AH_JOBCHANGEKEYS_L_H
#include "aqhbci_l.h"
#include "job_l.h"
AH_JOB *AH_Job_ChangeKeys_new(AB_PROVIDER *pro, AB_USER *u, GWEN_DB_NODE *args, uint8_t *canceled);
int AH_Job_ChangeKeys_finish(AB_PROVIDER *pro, AH_JOB *job, int res);
#endif
src/libs/plugins/backends/aqhbci/admjobs/jobchangekeys_p.h
#ifndef AH_JOBLOCKKEYS_P_H
#define AH_JOBLOCKKEYS_P_H
#include "jobchangekeys_l.h"
typedef struct AH_JOB_CHANGEKEYS AH_JOB_CHANGEKEYS;
#endif
src/libs/plugins/backends/aqhbci/banking/provider.c
/* admin jobs */
#include "jobgetkeys_l.h"
#include "jobsendkeys_l.h"
#include "jobchangekeys_l.h"
#include "jobgetsepainfo_l.h"
#include "jobgetsysid_l.h"
#include "jobgetbankinfo_l.h"
src/libs/plugins/backends/aqhbci/banking/provider.h
int withAuthKey,
int withProgress, int nounmount, int doLock);
/**
*/
int AH_Provider_ChangeUserKeys(AB_PROVIDER *pro, AB_USER *u, GWEN_DB_NODE *args, int withProgress, int nounmount, int doLock);
/**
* Retrieve the SSL certificate for the given user. This is only needed for
* PIN/TAN mode.
src/libs/plugins/backends/aqhbci/banking/provider_online.c
}
int AH_Provider_ChangeUserKeys(AB_PROVIDER *pro, AB_USER *u, GWEN_DB_NODE *args, int withProgress, int nounmount, int doLock)
{
int res = 0;
uint8_t canceled = 0;
AH_JOB *job = NULL;
AB_IMEXPORTER_CONTEXT *ctx = NULL;
assert(u);
job = AH_Job_ChangeKeys_new(pro, u, args, &canceled);
if(!job)
{
res = -2;
if(!canceled)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "Unexplainable, 'AH_Job_ChangeKeys_new' not supported.");
GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error, I18N("Unexplainable, 'AH_Job_ChangeKeys_new' not supported."));
res = -1;
}
if(canceled == 2)
res = -1;
}
if(!res)
{
ctx = AB_ImExporterContext_new();
if(!ctx)
{
DBG_ERROR(AQHBCI_LOGDOMAIN, "Error getting ctx.");
res = -1;
... Dieser Diff wurde abgeschnitten, weil er die maximale Anzahl anzuzeigender Zeilen überschreitet.
(1-1/2)