Revision 6c393ea7
Von admin vor etwa 6 Jahren hinzugefügt
| src/libs/plugins/backends/aqhbci/banking/provider_iniletter.c | ||
|---|---|---|
|
const char *fmtStr(char *buff, size_t buffLen, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
|
||
|
#define FB fmtBuff, sizeof(fmtBuff)
|
||
|
|
||
|
void dbgHexOut(unsigned const char *d, uint32_t l)
|
||
|
{
|
||
|
#if 0
|
||
|
uint32_t j = 0;
|
||
|
printf("\n");
|
||
|
for(uint32_t i = 0; i < l; i++, j++)
|
||
|
{
|
||
|
if(j >= 32)
|
||
|
{
|
||
|
printf("\n");
|
||
|
j = 0;
|
||
|
}
|
||
|
printf(" %02X", d[i]);
|
||
|
}
|
||
|
printf("\n\n");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int AH_Provider_GetIniLetter(AB_PROVIDER *pro, AB_USER *u, uint8_t useBankKey,
|
||
|
uint8_t outHtml, GWEN_BUFFER *lbuf, int nounmount);
|
||
|
|
||
| ... | ... | |
|
GWEN_BUFFER *lbuf;
|
||
|
int kn;
|
||
|
int kv;
|
||
|
uint8_t *e;
|
||
|
uint8_t *m;
|
||
|
const uint8_t *e;
|
||
|
const uint8_t *m;
|
||
|
uint32_t kl;
|
||
|
uint8_t *h;
|
||
|
const uint8_t *h;
|
||
|
uint32_t hl;
|
||
|
const char *hn;
|
||
|
};
|
||
| ... | ... | |
|
int IniLetterOutTxt(struct s_hashOut *h);
|
||
|
int IniLetterOutHtml(struct s_hashOut *h);
|
||
|
|
||
|
// XXX hash-len from algo-id?
|
||
|
#define HASHOUT_MAXLEN 32
|
||
|
|
||
|
int AH_Provider_GetIniLetter(AB_PROVIDER *pro, AB_USER *u, uint8_t useBankKey,
|
||
|
uint8_t outHtml, GWEN_BUFFER *lbuf, int nounmount)
|
||
|
{
|
||
|
char fmtBuff[256];
|
||
|
AH_HBCI *hbci = NULL;
|
||
|
AH_CRYPT_MODE cryptMode = AH_CryptMode_None;
|
||
|
int rdhType = 0;
|
||
|
int kn = 0, kv = 0;
|
||
|
GWEN_BUFFER *hBuff = NULL;
|
||
|
uint32_t eLen = 0, mLen = 0, hLen = 0;
|
||
|
uint8_t *mData = NULL, *eData = NULL;
|
||
|
GWEN_CRYPT_HASHALGOID hAlgo = GWEN_Crypt_HashAlgoId_Unknown;
|
||
|
uint8_t hOutBuff[HASHOUT_MAXLEN];
|
||
|
uint32_t hOutLen = 0;
|
||
|
const char *hName = NULL;
|
||
|
const char *emsg = NULL;
|
||
|
struct AH_KEYHASH *kh = NULL;
|
||
|
int rv = 0;
|
||
|
|
||
|
assert(pro);
|
||
| ... | ... | |
|
|
||
|
hbci = AH_Provider_GetHbci(pro);
|
||
|
|
||
|
memset(hOutBuff, 0, HASHOUT_MAXLEN);
|
||
|
|
||
|
cryptMode = AH_User_GetCryptMode(u);
|
||
|
rdhType = AH_User_GetRdhType(u);
|
||
|
switch(cryptMode)
|
||
|
kh = AH_Provider_KeyHash_new();
|
||
|
if(!kh)
|
||
|
{
|
||
|
case AH_CryptMode_Rdh:
|
||
|
switch(rdhType)
|
||
|
{
|
||
|
case 1:
|
||
|
case 2:
|
||
|
case 3:
|
||
|
case 5:
|
||
|
case 6:
|
||
|
case 7:
|
||
|
case 8:
|
||
|
case 9:
|
||
|
case 10:
|
||
|
break;
|
||
|
default:
|
||
|
rv = GWEN_ERROR_INVALID;
|
||
|
}
|
||
|
break;
|
||
|
case AH_CryptMode_Rah:
|
||
|
switch(rdhType)
|
||
|
{
|
||
|
case 7:
|
||
|
case 9:
|
||
|
case 10:
|
||
|
break;
|
||
|
default:
|
||
|
rv = GWEN_ERROR_INVALID;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
rv = GWEN_ERROR_INVALID;
|
||
|
DBG_ERROR(AQHBCI_LOGDOMAIN, "AH_Provider_KeyHash_new() failed.");
|
||
|
return GWEN_ERROR_GENERIC;
|
||
|
}
|
||
|
|
||
|
if(rv != 0)
|
||
|
emsg = fmtStr(FB, "Cryptmode %s%d not valid.", AH_CryptMode_toString(cryptMode), rdhType);
|
||
|
|
||
|
|
||
|
if(rv == 0)
|
||
|
if(useBankKey)
|
||
|
{
|
||
|
if(useBankKey)
|
||
|
// read bank-keys from config, keys from token may differ.
|
||
|
// if bank uses ini-letter, that *must* checked against sent key, which is actually in config
|
||
|
GWEN_CRYPT_KEY *key = AH_User_GetBankPubSignKey(u);
|
||
|
char kt = 'S';
|
||
|
if(!key)
|
||
|
{
|
||
|
// read bank-keys from config, keys from token may differ.
|
||
|
// if bank uses ini-letter, that *must* checked against sent key, which is actually in config
|
||
|
GWEN_CRYPT_KEY *key = AH_User_GetBankPubSignKey(u);
|
||
|
eLen = 3;
|
||
|
if(!key)
|
||
|
{
|
||
|
DBG_NOTICE(AQHBCI_LOGDOMAIN, "No signkey for bank, using cryptkey.");
|
||
|
key = AH_User_GetBankPubCryptKey(u);
|
||
|
}
|
||
|
if(!key)
|
||
|
{
|
||
|
DBG_ERROR(AQHBCI_LOGDOMAIN, "Server keys missing, please get them first.");
|
||
|
GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error, I18N("Server keys missing, please get them first."));
|
||
|
return GWEN_ERROR_NOT_FOUND;
|
||
|
}
|
||
|
mLen = GWEN_Crypt_Key_GetKeySize(key);
|
||
|
|
||
|
if(key && eLen && mLen)
|
||
|
{
|
||
|
kn = GWEN_Crypt_Key_GetKeyNumber(key);
|
||
|
kv = GWEN_Crypt_Key_GetKeyVersion(key);
|
||
|
mData = malloc(mLen);
|
||
|
eData = malloc(eLen);
|
||
|
rv = GWEN_Crypt_KeyRsa_GetModulus(key, mData, &mLen);
|
||
|
if(rv == 0)
|
||
|
GWEN_Crypt_KeyRsa_GetExponent(key, eData, &eLen);
|
||
|
if(rv != 0)
|
||
|
{
|
||
|
emsg = "Bad key.";
|
||
|
rv = GWEN_ERROR_BAD_DATA;
|
||
|
}
|
||
|
}
|
||
|
DBG_NOTICE(AQHBCI_LOGDOMAIN, "No signkey for bank, using cryptkey.");
|
||
|
key = AH_User_GetBankPubCryptKey(u);
|
||
|
kt = 'V';
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GWEN_CRYPT_TOKEN *ct = NULL;
|
||
|
const GWEN_CRYPT_TOKEN_KEYINFO *ki = NULL;
|
||
|
const GWEN_CRYPT_TOKEN_CONTEXT *ctx = NULL;
|
||
|
rv = AB_Banking_GetCryptToken(AH_HBCI_GetBankingApi(hbci), AH_User_GetTokenType(u), AH_User_GetTokenName(u), &ct);
|
||
|
if((rv != 0) || !ct)
|
||
|
{
|
||
|
emsg = fmtStr(FB, "Could not get crypt token (%d)", rv);
|
||
|
rv = GWEN_ERROR_GENERIC;
|
||
|
}
|
||
|
if(rv == 0)
|
||
|
{
|
||
|
rv = GWEN_Crypt_Token_Open(ct, 1, 0);
|
||
|
if(rv != 0)
|
||
|
{
|
||
|
emsg = fmtStr(FB, "Could not open crypt token (%d)", rv);
|
||
|
rv = GWEN_ERROR_GENERIC;
|
||
|
}
|
||
|
}
|
||
|
if(rv == 0)
|
||
|
{
|
||
|
ctx = GWEN_Crypt_Token_GetContext(ct, AH_User_GetTokenContextId(u), 0);
|
||
|
if(!ctx)
|
||
|
{
|
||
|
emsg = fmtStr(FB, "User context %d not found on crypt token", AH_User_GetTokenContextId(u));
|
||
|
rv = GWEN_ERROR_GENERIC;
|
||
|
}
|
||
|
}
|
||
|
if(rv == 0)
|
||
|
{
|
||
|
uint32_t kf = 0;
|
||
|
uint32_t kid = GWEN_Crypt_Token_Context_GetSignKeyId(ctx);
|
||
|
if(kid)
|
||
|
ki = GWEN_Crypt_Token_GetKeyInfo(ct, kid, 0, 0);
|
||
|
if(ki)
|
||
|
kf = GWEN_Crypt_Token_KeyInfo_GetFlags(ki);
|
||
|
if(!ki || !(kf & GWEN_CRYPT_TOKEN_KEYFLAGS_HASMODULUS) | !(kf & GWEN_CRYPT_TOKEN_KEYFLAGS_HASEXPONENT))
|
||
|
{
|
||
|
emsg = "User keys missing, please generate them first.";
|
||
|
rv = GWEN_ERROR_NOT_FOUND;
|
||
|
}
|
||
|
}
|
||
|
if(rv == 0)
|
||
|
{
|
||
|
const uint8_t *e = GWEN_Crypt_Token_KeyInfo_GetExponentData(ki);
|
||
|
const uint8_t *m = GWEN_Crypt_Token_KeyInfo_GetModulusData(ki);
|
||
|
eLen = GWEN_Crypt_Token_KeyInfo_GetExponentLen(ki);
|
||
|
mLen = GWEN_Crypt_Token_KeyInfo_GetModulusLen(ki);
|
||
|
if(!e || !eLen || !m || !mLen)
|
||
|
{
|
||
|
emsg = "Bad key.";
|
||
|
rv = GWEN_ERROR_BAD_DATA;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
kn = GWEN_Crypt_Token_KeyInfo_GetKeyNumber(ki);
|
||
|
kv = GWEN_Crypt_Token_KeyInfo_GetKeyVersion(ki);
|
||
|
mData = malloc(mLen);
|
||
|
eData = malloc(eLen);
|
||
|
memcpy(mData, m, mLen);
|
||
|
memcpy(eData, e, eLen);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(rv == 0)
|
||
|
{
|
||
|
switch(cryptMode)
|
||
|
if(!key)
|
||
|
{
|
||
|
case AH_CryptMode_Rdh:
|
||
|
switch(rdhType)
|
||
|
{
|
||
|
case 1:
|
||
|
hLen = 128 * 2;
|
||
|
hAlgo = GWEN_Crypt_HashAlgoId_Rmd160;
|
||
|
break;
|
||
|
case 2:
|
||
|
case 3:
|
||
|
case 5:
|
||
|
hLen = mLen * 2;
|
||
|
hAlgo = GWEN_Crypt_HashAlgoId_Rmd160;
|
||
|
break;
|
||
|
case 6:
|
||
|
case 7:
|
||
|
case 8:
|
||
|
case 9:
|
||
|
case 10:
|
||
|
// XXX EF_NOTEPAD, HBCI-Version C0=002
|
||
|
hAlgo = GWEN_Crypt_HashAlgoId_Sha256;
|
||
|
hLen = mLen * 2;
|
||
|
break;
|
||
|
default:;
|
||
|
}
|
||
|
case AH_CryptMode_Rah:
|
||
|
switch(rdhType)
|
||
|
{
|
||
|
case 7:
|
||
|
case 9:
|
||
|
case 10:
|
||
|
hAlgo = GWEN_Crypt_HashAlgoId_Sha256;
|
||
|
hLen = mLen * 2;
|
||
|
break;
|
||
|
default:;
|
||
|
}
|
||
|
default:;
|
||
|
DBG_ERROR(AQHBCI_LOGDOMAIN, "Server keys missing, please get them first.");
|
||
|
GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error, I18N("Server keys missing, please get them first."));
|
||
|
rv = GWEN_ERROR_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if((rv == 0) && ((mLen > (hLen / 2)) || (eLen > (hLen / 2))))
|
||
|
{
|
||
|
emsg = fmtStr(FB, "Invalid size for e, m, or h (%ld, %ld, %ld).", (long)eLen, (long)mLen, (long)hLen);
|
||
|
rv = GWEN_ERROR_GENERIC;
|
||
|
}
|
||
|
|
||
|
if(rv == 0)
|
||
|
{
|
||
|
if(hLen && eLen && mLen)
|
||
|
hBuff = GWEN_Buffer_new(0, hLen, 0, 1);
|
||
|
if(hBuff)
|
||
|
if(rv == 0)
|
||
|
{
|
||
|
GWEN_Buffer_FillWithBytes(hBuff, 0, (hLen / 2) - eLen);
|
||
|
GWEN_Buffer_AppendBytes(hBuff, (const char*)eData, eLen);
|
||
|
GWEN_Buffer_FillWithBytes(hBuff, 0, (hLen / 2) - mLen);
|
||
|
GWEN_Buffer_AppendBytes(hBuff, (const char*)mData, mLen);
|
||
|
GWEN_Buffer_Rewind(hBuff);
|
||
|
dbgHexOut((unsigned const char*)GWEN_Buffer_GetStart(hBuff), hLen);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(rv == 0)
|
||
|
{
|
||
|
switch(hAlgo)
|
||
|
{
|
||
|
case GWEN_Crypt_HashAlgoId_Rmd160:
|
||
|
hName = "RMD-160";
|
||
|
hOutLen = 20;
|
||
|
rv = AH_Provider__HashRmd160((const uint8_t*)GWEN_Buffer_GetStart(hBuff),
|
||
|
GWEN_Buffer_GetUsedBytes(hBuff), hOutBuff);
|
||
|
if(rv != 0)
|
||
|
emsg = fmtStr(FB, "AH_Provider__HashRmd160() failed (%d).", rv);
|
||
|
break;
|
||
|
case GWEN_Crypt_HashAlgoId_Sha256:
|
||
|
hName = "SHA-256";
|
||
|
hOutLen = 32;
|
||
|
rv = AH_Provider__HashSha256((const uint8_t*)GWEN_Buffer_GetStart(hBuff),
|
||
|
GWEN_Buffer_GetUsedBytes(hBuff), hOutBuff);
|
||
|
if(rv != 0)
|
||
|
emsg = fmtStr(FB, "AH_Provider__HashSha256() failed (%d).", rv);
|
||
|
break;
|
||
|
default:
|
||
|
emsg = "Hash algo not specified.";
|
||
|
rv = GWEN_ERROR_GENERIC;
|
||
|
rv = AH_Provider_GetKeyHash(AH_HBCI_GetProvider(hbci), u, key, kt, 0, 0, NULL, NULL, 0, NULL, 1, kh);
|
||
|
if(rv == GWEN_ERROR_NOT_FOUND)
|
||
|
emsg = "Server keys missing, please get them first.";
|
||
|
}
|
||
|
dbgHexOut(hOutBuff, hOutLen);
|
||
|
}
|
||
|
|
||
|
if((rv == 0) && (!hLen || !eLen || !eData || !mData || !hBuff || !hOutLen))
|
||
|
else
|
||
|
{
|
||
|
emsg = fmtStr(FB, "Internal error, bank %d, hLen %ld, eLen %ld, mLen %ld, e %p, m %p, hb %p, out %ld.",
|
||
|
useBankKey, (long)hLen, (long)eLen, (long)mLen, eData, mData, hBuff, (long)hOutLen);
|
||
|
rv = GWEN_ERROR_GENERIC;
|
||
|
rv = AH_Provider_GetKeyHash(AH_HBCI_GetProvider(hbci), u, NULL, 'S', 0, 0, NULL, NULL, 0, NULL, 0, kh);
|
||
|
if(rv == GWEN_ERROR_NOT_FOUND)
|
||
|
emsg = "User keys missing, please generate them first.";
|
||
|
}
|
||
|
|
||
|
DBG_NOTICE(AQHBCI_LOGDOMAIN, "bank %d, hLen %ld, eLen %ld, mLen %ld, e %p, m %p, hb %p, out %ld.",
|
||
|
useBankKey, (long)hLen, (long)eLen, (long)mLen, eData, mData, hBuff, (long)hOutLen);
|
||
|
|
||
|
if(rv == 0)
|
||
|
{
|
||
|
struct s_hashOut h;
|
||
|
uint8_t *eb = malloc(hLen / 2);
|
||
|
uint8_t *mb = malloc(hLen / 2);
|
||
|
memcpy(eb, GWEN_Buffer_GetStart(hBuff), hLen / 2);
|
||
|
memcpy(mb, GWEN_Buffer_GetStart(hBuff) + (hLen / 2), hLen / 2);
|
||
|
h.pro = pro;
|
||
|
h.isBankKey = useBankKey;
|
||
|
h.u = u;
|
||
|
h.lbuf = lbuf;
|
||
|
h.kn = kn;
|
||
|
h.kv = kv;
|
||
|
h.e = eb;
|
||
|
h.m = mb;
|
||
|
h.kl = hLen / 2;
|
||
|
h.h = hOutBuff;
|
||
|
h.hl = hOutLen;
|
||
|
h.hn = hName;
|
||
|
AH_Provider_KeyHash_Info(kh, &h.kn, &h.kv, &h.hn);
|
||
|
h.e = AH_Provider_KeyHash_Exponent(kh, &h.kl);;
|
||
|
h.m = AH_Provider_KeyHash_Modulus(kh, &h.kl);
|
||
|
h.h = AH_Provider_KeyHash_Hash(kh, &h.hl);;
|
||
|
DBG_NOTICE(AQHBCI_LOGDOMAIN, "bank %d, kLen %ld, e %p, m %p, hb %p, out %ld.",
|
||
|
useBankKey, (long)h.kl, h.e, h.m, h.h, (long)h.hl);
|
||
|
if(!outHtml)
|
||
|
rv = IniLetterOutTxt(&h);
|
||
|
else
|
||
|
rv = IniLetterOutHtml(&h);
|
||
|
free(eb);
|
||
|
free(mb);
|
||
|
}
|
||
|
|
||
|
if(hBuff)
|
||
|
GWEN_Buffer_free(hBuff);
|
||
|
free(eData);
|
||
|
free(mData);
|
||
|
AH_Provider_KeyHash_free(kh);
|
||
|
|
||
|
if(rv != 0)
|
||
|
{
|
||
| ... | ... | |
|
|
||
|
if(!nounmount)
|
||
|
AB_Banking_ClearCryptTokenList(AH_HBCI_GetBankingApi(hbci));
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
Auch abrufbar als: Unified diff
AqHBCI: Patch by thbe (aqb-iniletter-getkeyhash.patch).