1 /***************************************************************************
2
3 ***************************************************************************
4 * Please see toplevel file COPYING for license details *
5 ***************************************************************************/
6
7
8 #ifdef HAVE_CONFIG_H
9 # include <config.h>
10 #endif
11
12
13 #include "jobchangekeys_p.h"
14 #include "../banking/user_l.h"
15 #include "../banking/provider_l.h"
16 #include "aqhbci/joblayer/job_crypt.h"
17 #include <gwenhywfar/ctplugin.h>
18 #include <gwenhywfar/ctfile_be.h>
19
20 #include <stdarg.h>
21 #include <unistd.h>
22
23
24 /*
25 Moegliche Wechsel:
26
27 medium type mode
28
29 datei RDH 1 karte o. cert RAH 9
30 datei RDH 1 datei RAH 10
31 karte o. cert RDH 1 karte o. cert RAH 9
32 datei RDH 2 karte o. cert RAH 9
33 datei RDH 2 datei RAH 10
34 karte o. cert RDH 5 karte o. cert RAH 9
35
36 ohne Schluesselwechsel:
37 karte o. cert RDH 9 karte o. cert RAH 9
38 datei RDH 10 karte o. cert RAH 9
39 datei RDH 10 datei RAH 10
40 */
41
42
43 GWEN_INHERIT(AH_JOB, AH_JOB_CHANGEKEYS)
44
45 const char *fmtStr(char *buff, size_t buffLen, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
fmtStr(char * buff,size_t buffLen,const char * fmt,...)46 const char *fmtStr(char *buff, size_t buffLen, const char *fmt, ...)
47 {
48 va_list args;
49 va_start(args, fmt);
50 vsnprintf(buff, buffLen - 1, fmt, args);
51 buff[buffLen - 1] = 0;
52 va_end(args);
53 return buff;
54 }
55
56 #define FB fmtBuff, sizeof(fmtBuff)
57
onError(const char * m,int rv)58 int onError(const char *m, int rv)
59 {
60 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s", m);
61 GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_ERROR,
62 I18N("Change keys: error"), I18N(m), I18N("OK"), NULL, NULL, 0);
63 return rv;
64 }
65
66
67
strUpper(char * s)68 const char *strUpper(char *s)
69 {
70 size_t i;
71 size_t l = strlen(s);
72 for (i = 0; i < l; i++) {
73 if ((s[i] >= 'a') && (s[i] <= 'z'))
74 s[i] -= 0x20;
75
76 }
77 return s;
78 }
79
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 ** cryptKeyInfo,const GWEN_CRYPT_TOKEN_KEYINFO ** signKeyInfo,const GWEN_CRYPT_TOKEN_KEYINFO ** authKeyInfo)80 int8_t getKeyInfo(AH_HBCI *h, const char *tt, const char *tn, uint32_t cid, GWEN_CRYPT_TOKEN **ct,
81 const GWEN_CRYPT_TOKEN_CONTEXT **ctx,
82 const GWEN_CRYPT_TOKEN_KEYINFO **cryptKeyInfo, const GWEN_CRYPT_TOKEN_KEYINFO **signKeyInfo,
83 const GWEN_CRYPT_TOKEN_KEYINFO **authKeyInfo)
84 {
85 int8_t res = 0;
86 uint8_t i;
87
88 uint32_t f = GWEN_CRYPT_TOKEN_KEYFLAGS_HASMODULUS | GWEN_CRYPT_TOKEN_KEYFLAGS_HASEXPONENT |
89 GWEN_CRYPT_TOKEN_KEYFLAGS_HASKEYVERSION | GWEN_CRYPT_TOKEN_KEYFLAGS_HASKEYNUMBER;
90 if (!*ct && (((AB_Banking_GetCryptToken(AH_HBCI_GetBankingApi(h), tt, tn, ct) < 0)) || !*ct)) {
91 DBG_ERROR(AQHBCI_LOGDOMAIN, "AB_Banking_GetCryptToken() failed (tt '%s', tn '%s').", tt, tn);
92 return -1;
93 }
94 if (GWEN_Crypt_Token_Open(*ct, 0, 0) < 0) {
95 DBG_ERROR(AQHBCI_LOGDOMAIN, "GWEN_Crypt_Token_Open() failed.");
96 return -1;
97 }
98 *ctx = GWEN_Crypt_Token_GetContext(*ct, cid, 0);
99 if (!*ctx) {
100 DBG_ERROR(AQHBCI_LOGDOMAIN, "GWEN_Crypt_Token_GetContext() failed (cid %ld).", (long)cid);
101 return -1;
102 }
103 for (i = 0; i < 3; i++) {
104 uint32_t kid = 0;
105 const GWEN_CRYPT_TOKEN_KEYINFO **ki = NULL;
106 char kl = '?';
107 switch (i) {
108 case 0:
109 kid = GWEN_Crypt_Token_Context_GetDecipherKeyId(*ctx);
110 ki = cryptKeyInfo, kl = 'V';
111 break;
112 case 1:
113 kid = GWEN_Crypt_Token_Context_GetSignKeyId(*ctx);
114 ki = signKeyInfo;
115 kl = 'S';
116 break;
117 case 2:
118 kid = GWEN_Crypt_Token_Context_GetAuthSignKeyId(*ctx);
119 ki = authKeyInfo;
120 kl = 'D';
121 break;
122 }
123 if ((kl == 'D') && !strcmp(tt, "ddvcard"))
124 continue;
125 if ((*ki = GWEN_Crypt_Token_GetKeyInfo(*ct, kid, f, 0)) == NULL) {
126 DBG_ERROR(AQHBCI_LOGDOMAIN, "GWEN_Crypt_Token_GetKeyInfo() (%c) failed.", kl);
127 res = -1;
128 break;
129 }
130 }
131 return res;
132 }
133
tokenHasKeys(GWEN_CRYPT_TOKEN * ct,const GWEN_CRYPT_TOKEN_CONTEXT * ctx)134 int8_t tokenHasKeys(GWEN_CRYPT_TOKEN *ct, const GWEN_CRYPT_TOKEN_CONTEXT *ctx)
135 {
136 uint8_t i;
137 int8_t res = 2;
138 for (i = 0; (res > 0) && (i < 2); i++) {
139 const GWEN_CRYPT_TOKEN_KEYINFO *ki = NULL;
140 int kn = 0, kv = 0;
141 uint32_t flags = 0;
142 uint32_t id = (i == 0) ? GWEN_Crypt_Token_Context_GetDecipherKeyId(ctx) : GWEN_Crypt_Token_Context_GetVerifyKeyId(ctx);
143 if (res == 2)
144 res = 1;
145 if (!id)
146 res = -1;
147 else
148 ki = GWEN_Crypt_Token_GetKeyInfo(ct, id, 0, 0);
149 if (!ki)
150 res = -1;
151 else {
152 kn = GWEN_Crypt_Token_KeyInfo_GetKeyNumber(ki);
153 kv = GWEN_Crypt_Token_KeyInfo_GetKeyVersion(ki);
154 flags = GWEN_Crypt_Token_KeyInfo_GetFlags(ki);
155 }
156 if ((res >= 0) && (!kn || !kv || !(flags & GWEN_CRYPT_TOKEN_KEYFLAGS_HASMODULUS) ||
157 !(flags & GWEN_CRYPT_TOKEN_KEYFLAGS_HASEXPONENT)))
158 res = 0;
159 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): id %ld %d %d m %d e %d -> %d.", __FUNCTION__, (long)id, kn, kv,
160 (flags & GWEN_CRYPT_TOKEN_KEYFLAGS_HASMODULUS) != 0, (flags & GWEN_CRYPT_TOKEN_KEYFLAGS_HASEXPONENT) != 0, res);
161 }
162 return (res == 1) ? 1 : 0;
163 }
164
165 #if 1
setKeyVersion(GWEN_CRYPT_TOKEN * ct,const GWEN_CRYPT_TOKEN_CONTEXT * ctx,const GWEN_CRYPT_TOKEN_KEYINFO * ki,char t,uint32_t kv)166 int8_t setKeyVersion(GWEN_CRYPT_TOKEN *ct, const GWEN_CRYPT_TOKEN_CONTEXT *ctx, const GWEN_CRYPT_TOKEN_KEYINFO *ki,
167 char t, uint32_t kv)
168 {
169 int8_t ret = 0;
170 GWEN_CRYPT_TOKEN_KEYINFO *kin = NULL;
171 uint32_t kid = 0;
172
173 switch (t) {
174 case 'V':
175 kid = GWEN_Crypt_Token_Context_GetDecipherKeyId(ctx);
176 break;
177 case 'S':
178 kid = GWEN_Crypt_Token_Context_GetSignKeyId(ctx);
179 break;
180 case 'A':
181 kid = GWEN_Crypt_Token_Context_GetAuthSignKeyId(ctx);
182 break;
183 default:
184 DBG_ERROR(AQHBCI_LOGDOMAIN, "type %c invalid.", t);
185 return -1;
186 }
187
188 kin = GWEN_Crypt_Token_KeyInfo_dup(ki);
189
190 if (kv > 999)
191 kv = 1;
192 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): key %ld '%c' set version %ld.", __FUNCTION__, (long)kid, t, (long)kv);
193 GWEN_Crypt_Token_KeyInfo_SetKeyVersion(kin, kv);
194 if (GWEN_Crypt_Token_SetKeyInfo(ct, kid, kin, 0)) {
195 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): GWEN_Crypt_Token_SetKeyInfo() failed.", __FUNCTION__);
196 ret = -1;
197 }
198 GWEN_Crypt_Token_KeyInfo_free(kin);
199 if (ret)
200 return ret;
201 if ((ret == 0) && (ki = GWEN_Crypt_Token_GetKeyInfo(ct, kid, 0, 0)) == NULL) {
202 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): GWEN_Crypt_Token_GetKeyInfo() (%c) failed.", __FUNCTION__, t);
203 ret = -1;
204 }
205 if (ret)
206 return ret;
207 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): key '%c' version now %d.", __FUNCTION__, t,
208 GWEN_Crypt_Token_KeyInfo_GetKeyVersion(ki));
209 return 0;
210 }
211 #endif
212
213 #define FJCK_CHMEDIA 1
214 #define FJCK_CHKEY 2
215 #define FJCK_CHPROFILE 4
216 #define FJCK_SRCFILE 8
217 #define FJCK_DSTFILE 16
218 #define FJCK_DSTFILE_EXISTS 32
219
220 void GWENHYWFAR_CB GWENHYWFAR_CB AH_Job_ChangeKeys_FreeData(void *bp, void *p);
221 int AH_Job_ChangeKeys_NextMsg(AH_JOB *j);
222
AH_Job_ChangeKeys_new(AB_PROVIDER * pro,AB_USER * u,GWEN_DB_NODE * args,uint8_t * canceled)223 AH_JOB *AH_Job_ChangeKeys_new(AB_PROVIDER *pro, AB_USER *u, GWEN_DB_NODE *args, uint8_t *canceled)
224 {
225 int res = 0;
226 char fmtBuff[256];
227 AH_JOB *j = NULL;
228 AH_JOB_CHANGEKEYS *jd = NULL;
229 AB_USER *uTmp = NULL;
230 AH_HBCI *h = AH_Provider_GetHbci(pro);
231 uint16_t flags = FJCK_CHKEY | FJCK_CHMEDIA | FJCK_CHPROFILE;
232 AH_CRYPT_MODE cryptModeNew = AH_CryptMode_None;
233 int cryptTypeNew = -1;
234 int tokenCtxIdNew = -1;
235 const char *tokenTypeFromToken = NULL;
236 const char *tokenNameFromToken = NULL;
237 char *wantedTokenType = NULL, *wantedTokenName = NULL;
238 const char *wantedCryptMode = NULL;
239 GWEN_CRYPT_TOKEN *ct = NULL, *ctNew = NULL;
240 const GWEN_CRYPT_TOKEN_CONTEXT *ctx = NULL, *ctxNew = NULL;
241 const GWEN_CRYPT_TOKEN_KEYINFO *cryptKeyInfo = NULL, *signKeyInfo = NULL, *authKeyInfo = NULL, *kiVNew = NULL,
242 *kiSNew = NULL, *kiANew = NULL;
243 GWEN_PLUGIN *plg = NULL;
244 GWEN_PLUGIN_MANAGER *pm = GWEN_PluginManager_FindPluginManager(GWEN_CRYPT_TOKEN_PLUGIN_TYPENAME);
245 const char *cmn = "?", *fm = "?", *fmn = "?";
246
247 assert(h);
248
249 //GWEN_DB_Dump(args, 0);
250 wantedTokenType = strdup(GWEN_DB_GetCharValue(args, "tokenType", 0, ""));
251 wantedTokenName = strdup(GWEN_DB_GetCharValue(args, "tokenName", 0, ""));
252 wantedCryptMode = GWEN_DB_GetCharValue(args, "cryptMode", 0, "");
253 cryptTypeNew = GWEN_DB_GetIntValue(args, "cryptType", 0, -1);
254 tokenCtxIdNew = GWEN_DB_GetIntValue(args, "context", 0, -1);
255
256 if (wantedCryptMode && *wantedCryptMode) {
257 if (!strcasecmp(wantedCryptMode, "RDH"))
258 cryptModeNew = AH_CryptMode_Rdh;
259 else if (!strcasecmp(wantedCryptMode, "RAH"))
260 cryptModeNew = AH_CryptMode_Rah;
261 }
262
263 tokenTypeFromToken = AH_User_GetTokenType(u);
264 tokenNameFromToken = AH_User_GetTokenName(u);
265 if (!strcasecmp(tokenTypeFromToken, "ohbci"))
266 flags |= FJCK_SRCFILE;
267 if (!*wantedTokenType) {
268 free(wantedTokenType);
269 wantedTokenType = NULL;
270 if (*wantedTokenName && !strchr(wantedTokenName, '/') && !strchr(wantedTokenName, '\\')) { // assume thats a card number
271 size_t l = strlen(wantedTokenName);
272 size_t i = 0;
273 for (; i < l; i++) {
274 if ((wantedTokenName[i] < '0') || (wantedTokenName[i] > '9'))
275 break;
276 }
277 if (i == l) {
278 wantedTokenType = strdup("card");
279 if (l < 10) {
280 char *tmp = strdup("0000000000");
281 for (i = 0; i < l; i++)
282 tmp[9 - i] = wantedTokenName[(l - 1) - i];
283 free(wantedTokenName);
284 wantedTokenName = tmp;
285 }
286 }
287 }
288 }
289 if (wantedTokenType && !*wantedTokenType) {
290 free(wantedTokenType);
291 wantedTokenType = NULL;
292 }
293 if (!wantedTokenType)
294 wantedTokenType = strdup(tokenTypeFromToken);
295 if (!strcasecmp(wantedTokenType, "file") || !strcasecmp(wantedTokenType, "ohbci")) {
296 flags |= FJCK_DSTFILE;
297 free(wantedTokenType);
298 wantedTokenType = strdup("ohbci");
299 }
300 else if (!strstr(wantedTokenType, "card"))
301 res = onError(fmtStr(FB, "Invalid token-type '%s'.", wantedTokenType), -1);
302 if (!*wantedTokenName) {
303 free(wantedTokenName);
304 wantedTokenName = strdup(tokenNameFromToken);
305 if (!strcasecmp(tokenTypeFromToken, "ohbci"))
306 flags |= FJCK_DSTFILE;
307 }
308
309 if (res == 0) {
310 if (!access(wantedTokenName, F_OK))
311 flags |= FJCK_DSTFILE_EXISTS;
312
313 if (!strcasecmp(tokenTypeFromToken, wantedTokenType) && !strcmp(tokenNameFromToken, wantedTokenName)) {
314 if (cryptModeNew == AH_CryptMode_None)
315 cryptModeNew = AH_User_GetCryptMode(u);
316 if (cryptTypeNew < 0)
317 cryptTypeNew = AH_User_GetRdhType(u);
318 }
319 if (cryptModeNew == AH_CryptMode_None)
320 res = onError("Crypt-mode must be specified.", -1);
321 if ((res == 0) && (cryptTypeNew < 0))
322 res = onError("Crypt-typ must specified.", -1);
323 }
324
325 if (tokenCtxIdNew < 0)
326 tokenCtxIdNew = 1;
327
328 fm = (flags & FJCK_SRCFILE) ? "Keyfile" : "Chipcard";
329 fmn = (flags & FJCK_DSTFILE) ? "Keyfile" : "Chipcard";
330
331 DBG_INFO(AQHBCI_LOGDOMAIN, "'%s' '%s' -> '%s' '%s', file %d exists %d'.",
332 tokenTypeFromToken, tokenNameFromToken, wantedTokenType, wantedTokenName, (flags & FJCK_DSTFILE) != 0,
333 (flags & FJCK_DSTFILE_EXISTS) != 0);
334
335 if (res == 0) {
336 if (
337 (!((flags & FJCK_SRCFILE)) == !((flags & FJCK_DSTFILE))) &&
338 !strcmp(tokenNameFromToken, wantedTokenName)
339 )
340 res = onError("Keychange without media change is not supported, yet.", -1);
341 }
342
343 if (res == 0) {
344 switch (cryptModeNew) {
345 case AH_CryptMode_Rah:
346 cmn = "RAH";
347 break;
348 case AH_CryptMode_Rdh:
349 cmn = "RDH";
350 break;
351 default:
352 cmn = "unknown";
353 }
354 if (!strcasecmp(tokenTypeFromToken, wantedTokenType) && !strcmp(tokenNameFromToken, wantedTokenName))
355 flags &= ~FJCK_CHMEDIA;
356 if ((AH_User_GetCryptMode(u) == cryptModeNew) && (AH_User_GetRdhType(u) == cryptTypeNew))
357 flags &= ~FJCK_CHPROFILE;
358 DBG_INFO(AQHBCI_LOGDOMAIN, "'%s %d' -> '%s' '%s' '%s %d', change: m %d, k %d, p %d.",
359 AH_CryptMode_toString(AH_User_GetCryptMode(u)), AH_User_GetRdhType(u),
360 wantedTokenType, wantedTokenName, AH_CryptMode_toString(cryptModeNew), cryptTypeNew, (flags & FJCK_CHMEDIA) != 0,
361 (flags & FJCK_CHKEY) != 0,
362 (flags & FJCK_CHPROFILE) != 0);
363 if (flags & FJCK_CHPROFILE) {
364 res = -1;
365 switch (AH_User_GetCryptMode(u)) {
366 case AH_CryptMode_Rdh:
367 switch (cryptModeNew) {
368 case AH_CryptMode_Rdh:
369 onError("Änderung des Schlüsselsprofils nach RDH nicht unterstützt.", -1);
370 break;
371 default:
372 if (!(flags & FJCK_SRCFILE) && !(flags & FJCK_DSTFILE) && (AH_User_GetRdhType(u) == 9) && (cryptTypeNew == 9))
373 res = 1;
374 else if ((flags & FJCK_SRCFILE) && !(flags & FJCK_DSTFILE) && (AH_User_GetRdhType(u) == 10) && (cryptTypeNew == 9))
375 res = 1;
376 else if ((flags & FJCK_SRCFILE) && (flags & FJCK_DSTFILE) && (AH_User_GetRdhType(u) == 10) && (cryptTypeNew == 10))
377 res = 1;
378 if (res == 1) {
379 flags &= ~FJCK_CHKEY;
380 res = 0;
381 }
382 else {
383 if (flags & FJCK_SRCFILE) {
384 switch (AH_User_GetRdhType(u)) {
385 case 1:
386 case 2:
387 if (!(flags & FJCK_DSTFILE) && (cryptTypeNew == 9))
388 res = 0;
389 if ((flags & FJCK_DSTFILE) && (cryptTypeNew == 10))
390 res = 0;
391 break;
392 default:
393 ;
394 }
395 }
396 else {
397 switch (AH_User_GetRdhType(u)) {
398 case 1:
399 case 5:
400 if (!(flags & FJCK_DSTFILE) && (cryptTypeNew == 9))
401 res = 0;
402 break;
403 default:
404 ;
405 }
406 }
407 if (res)
408 onError(fmtStr(FB, "Aenderung des Schluesselsprofils von %s RDH-%d nach %s RAH-%d nicht unterstuetzt.",
409 fm, AH_User_GetRdhType(u), fmn, cryptTypeNew), -1);
410 }
411 }
412 break;
413 default:
414 onError("Aenderung des Sicherheitsprofils nur von RDH aus unterstuetzt.", -1);
415 }
416 }
417 if (res)
418 *canceled = 2;
419 }
420
421 if (res == 0) {
422 // keyinfo current token
423 if (getKeyInfo(h, AH_User_GetTokenType(u), AH_User_GetTokenName(u), AH_User_GetTokenContextId(u), &ct, &ctx,
424 &cryptKeyInfo, &signKeyInfo,
425 &authKeyInfo)
426 || !ct || !ctx || !cryptKeyInfo || !signKeyInfo || !authKeyInfo) {
427 DBG_INFO(AQHBCI_LOGDOMAIN, "getKeyInfo() ct %p, ctx %p, ki %p %p %p.", ct, ctx, cryptKeyInfo, signKeyInfo, authKeyInfo);
428 if (!ct || !ctx)
429 res = onError("Could not get token.", -1);
430 else
431 res = onError("Crypt token type not suitable for this operation.", -1);
432 }
433 }
434
435 if ((res == 0) && (flags & FJCK_CHMEDIA)) {
436 char *tokenNew = NULL;
437 if (!strcmp(wantedTokenType, "card")) {
438 GWEN_BUFFER *ctn = GWEN_Buffer_new(0, 64, 0, 1);
439 GWEN_BUFFER *cmn = GWEN_Buffer_new(0, 64, 0, 1);
440 for (; res == 0;) {
441 res = AB_Banking_CheckCryptToken(AB_Provider_GetBanking(pro), GWEN_Crypt_Token_Device_Card, ctn, cmn);
442 DBG_INFO(AQHBCI_LOGDOMAIN, "card: '%s' '%s'.", GWEN_Buffer_GetStart(ctn), GWEN_Buffer_GetStart(cmn));
443 if (res)
444 res = onError("AB_Banking_CheckCryptToken() failed.", -1);
445 else {
446 if (tokenNew)
447 free(tokenNew);
448 tokenNew = strdup(GWEN_Buffer_GetStart(ctn));
449 if (!strcmp(wantedTokenName, GWEN_Buffer_GetStart(cmn)))
450 break;
451 if (GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: insert card"),
452 fmtStr(FB, "Chipcard '%s' needed.", wantedTokenName), I18N("Abort"), I18N("OK"), NULL, 0) != 2)
453 res = -2;
454 }
455 }
456 GWEN_Buffer_free(ctn);
457 GWEN_Buffer_free(cmn);
458 if (tokenNew) {
459 free(wantedTokenType);
460 wantedTokenType = tokenNew;
461 tokenNew = NULL;
462 }
463 }
464
465 if (tokenNew)
466 free(tokenNew);
467
468 if (res == 0)
469 plg = GWEN_PluginManager_GetPlugin(pm, wantedTokenType);
470 if (!plg && (res == 0))
471 res = onError(fmtStr(FB, "Could not get plugin for new tokentype '%s'.", wantedTokenType), -1);
472 if (plg && (flags & FJCK_DSTFILE)) {
473 // diff. context?
474 if ((flags & FJCK_SRCFILE) && !strcmp(tokenNameFromToken, wantedTokenName))
475 res = onError(fmtStr(FB, "New and old keyfile must be different."), -1);
476 else {
477 uint8_t del = 1;
478 tokenCtxIdNew = 1;
479 if (flags & FJCK_DSTFILE_EXISTS) {
480 del = 0;
481 res = GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
482 fmtStr(FB, "Keyfile '%s' already exists.", wantedTokenName), I18N("Abort"), I18N("Use"), I18N("Delete"), 0);
483 if (res == 1)
484 res = -1;
485 else if (res == 2) { // use
486 res = 0;
487 //flags &= ~FJCK_CHKEY;
488 if (getKeyInfo(h, wantedTokenType, wantedTokenName, tokenCtxIdNew, &ctNew, &ctxNew, &kiVNew, &kiSNew, &kiANew)
489 || !ctNew || !ctxNew || !kiVNew || !kiSNew || !kiANew)
490 res = onError("Could not get token for new keyfile.", -1);
491 }
492 else if (GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
493 fmtStr(FB, "Really delete keyfile '%s'?", wantedTokenName), I18N("Abort"), I18N("Delete"), NULL, 0) != 2)
494 res = -1;
495 else {
496 res = 0;
497 del = 1;
498 }
499 if (res) {
500 res = onError("Canceled.", -1);
501 *canceled = 1;
502 }
503 else if (del)
504 unlink(wantedTokenName);
505 }
506 if ((res == 0) && del) {
507 if (GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
508 fmtStr(FB, "Schlüsseldatei '%s' wird erzeugt.", wantedTokenName), I18N("Abort"), I18N("OK"), NULL, 0) != 2) {
509 res = onError("Canceled.", -1);
510 *canceled = 1;
511 }
512 if (res == 0) {
513 ctNew = GWEN_Crypt_Token_Plugin_CreateToken(plg, wantedTokenName);
514 if (!ctNew)
515 res = onError(fmtStr(FB, "Could not create crypt token '%s'.", wantedTokenName), -1);
516 else if (GWEN_Crypt_Token_Create(ctNew, 0) < 0)
517 res = onError(fmtStr(FB, "Could not create keyfile '%s'.", GWEN_Crypt_Token_GetTokenName(ctNew)), -1);
518 else if (GWEN_Crypt_Token_Close(ctNew, 0, 0))
519 res = onError("Could not close token.", -1);
520 }
521 }
522 }
523 }
524 // keyinfo dest. token
525 if (res == 0) {
526 if (getKeyInfo(h, wantedTokenType, wantedTokenName, tokenCtxIdNew, &ctNew, &ctxNew, &kiVNew, &kiSNew, &kiANew)
527 || !ctNew || !ctxNew || !kiVNew || !kiSNew || !kiANew) {
528 DBG_NOTICE(AQHBCI_LOGDOMAIN, "getKeyInfo() ct %p, ctx %p, ki %p %p %p.", ct, ctx, cryptKeyInfo, signKeyInfo,
529 authKeyInfo);
530 if (!ct || !ctx)
531 res = onError("Could not get token.", -1);
532 else
533 res = onError("Crypt token not suitable for this operation.", -1);
534 }
535 }
536 if ((res == 0) && !(flags & FJCK_DSTFILE)) {
537 int tnV = GWEN_Crypt_Token_KeyInfo_GetKeyNumber(kiVNew);
538 int tnS = GWEN_Crypt_Token_KeyInfo_GetKeyNumber(kiSNew);
539 if ((cryptTypeNew != tnV) || (cryptTypeNew != tnS)) {
540 DBG_ERROR(AQHBCI_LOGDOMAIN, "rdh-type %d, card %d/%d..", cryptTypeNew, tnV, tnS);
541 res = onError("Target crypt token not suitable for thius operation.", -1);
542 }
543 }
544 }
545 #if 1
546 if (res == 0) {
547 // how get key-pair from token?
548 if (!(flags & FJCK_CHKEY) && (flags & FJCK_CHMEDIA))
549 res = onError("Change of security profile without change of crypt token not implemented.", -1);
550 }
551 #endif
552 if (res == 0) {
553 if (flags & FJCK_CHMEDIA) {
554 char *cm = strdup(AH_CryptMode_toString(AH_User_GetCryptMode(u)));
555 const char *m = fmtStr(FB, "Change crypt token from\n %s '%s', %s-%d\nto\n %s '%s', %s-%d?",
556 fm, tokenNameFromToken, strUpper(cm), AH_User_GetRdhType(u), fmn, wantedTokenName, cmn, cryptTypeNew);
557 free(cm);
558 if (GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
559 m, I18N("Abort"), I18N("OK"), NULL, 0) != 2) {
560 res = -1;
561 *canceled = 1;
562 }
563 }
564 }
565
566 if (res == 0) {
567 uTmp = AB_Provider_CreateUserObject(pro);
568 AH_User_SetCryptMode(uTmp, cryptModeNew);
569 AH_User_SetRdhType(uTmp, cryptTypeNew);
570 AH_User_SetTokenType(uTmp, wantedTokenType);
571 AH_User_SetTokenName(uTmp, wantedTokenName);
572 AH_User_SetTokenContextId(uTmp, tokenCtxIdNew);
573 AB_User_SetBankCode(uTmp, AB_User_GetBankCode(u));
574 AH_User_SetHbciVersion(uTmp, AH_User_GetHbciVersion(u));
575 AH_User_SetServerUrl(uTmp, AH_User_GetServerUrl(u));
576
577 DBG_NOTICE(AQHBCI_LOGDOMAIN, "chng k %d p %d m %d, token: open %d ctx %d knr dst %d %d %d.",
578 (flags & FJCK_CHKEY) != 0, (flags & FJCK_CHPROFILE) != 0, (flags & FJCK_CHMEDIA) != 0, GWEN_Crypt_Token_IsOpen(ctNew),
579 tokenCtxIdNew,
580 kiVNew ? GWEN_Crypt_Token_KeyInfo_GetKeyNumber(kiVNew) : - 1,
581 kiSNew ? GWEN_Crypt_Token_KeyInfo_GetKeyNumber(kiSNew) : -1,
582 kiANew ? GWEN_Crypt_Token_KeyInfo_GetKeyNumber(kiANew) : -1);
583 }
584
585 if (res == 0) {
586 j = AH_Job_new((flags & FJCK_DSTFILE) ? "JobChangeKeys" : "JobChangeKeysA", pro, u, NULL, 0);
587 DBG_INFO(AQHBCI_LOGDOMAIN, "%s(): j %p u %p '%s'.", __FUNCTION__, j, u, j ? AH_Job_GetCode(j) : "-");
588 if (!j)
589 res = onError("AH_Job_new() failed.", -1);
590 }
591
592 if (res == 0) {
593 GWEN_NEW_OBJECT(AH_JOB_CHANGEKEYS, jd);
594 GWEN_INHERIT_SETDATA(AH_JOB, AH_JOB_CHANGEKEYS, j, jd, AH_Job_ChangeKeys_FreeData);
595
596 AH_Job_SetNextMsgFn(j, AH_Job_ChangeKeys_NextMsg);
597
598 args = AH_Job_GetArguments(j);
599 assert(args);
600 }
601
602 if (res == 0) {
603 char *cm = strdup(AH_CryptMode_toString(cryptModeNew));
604 uint8_t i;
605
606 strUpper(cm);
607 for (i = 0; i < 3; i++) {
608 const char *kt = "?";
609 GWEN_DB_NODE *db = NULL;
610
611 if (i < 2) {
612 switch (i) {
613 case 0:
614 kt = "V";
615 db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "getcryptKey");
616 break;
617 case 1:
618 kt = "S";
619 db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "getsignKey");
620 break;
621 }
622
623 // HKISA
624 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "secProfile/code", cm);
625 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "secProfile/version", cryptTypeNew);
626
627 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/userid", AH_User_GetPeerId(u));
628 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/keyType", kt);
629 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/keynum", 999);
630 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/keyversion", 999);
631 }
632
633 switch (i) {
634 case 0:
635 kt = "V";
636 db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "setcryptKey");
637 break;
638 case 1:
639 kt = "S";
640 db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "setsignKey");
641 break;
642 case 2:
643 kt = "D";
644 db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "setauthKey");
645 break;
646 }
647 // HKSAK
648 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "secProfile/code", cm);
649 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "secProfile/version", cryptTypeNew);
650 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/userid", AH_User_GetPeerId(u));
651 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/keyType", kt);
652 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "keyName/keyType", kt);
653 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "keyName/userid", AH_User_GetPeerId(u));
654 }
655 free(cm);
656 }
657 if (res) {
658 if (j)
659 AH_Job_free(j);
660 j = NULL;
661 if (res == -2)
662 *canceled = 2;
663 }
664
665 if (jd) {
666 jd->flags = flags;
667 jd->canceled = canceled;
668 jd->pro = pro;
669 jd->u = u;
670 jd->uTmp = uTmp;
671 jd->fm = fmn;
672 jd->tokenType = wantedTokenType;
673 jd->tokenName = wantedTokenName;
674 jd->currentCryptKeyVersion = cryptKeyInfo ? GWEN_Crypt_Token_KeyInfo_GetKeyVersion(cryptKeyInfo) : 0;
675 jd->currentSignKeyVersion = signKeyInfo ? GWEN_Crypt_Token_KeyInfo_GetKeyVersion(signKeyInfo) : 0;
676 jd->currentAuthKeyVersion = authKeyInfo ? GWEN_Crypt_Token_KeyInfo_GetKeyVersion(authKeyInfo) : 0;
677 jd->ct = ctNew;
678 jd->ctx = ctxNew;
679 jd->tokenCtxId = tokenCtxIdNew;
680 jd->cryptKeyInfo = kiVNew;
681 jd->signKeyInfo = kiSNew;
682 jd->authKeyInfo = kiANew;
683 jd->resp = -1;
684 jd->emsg = NULL;
685 }
686
687 if (ctNew)
688 GWEN_Crypt_Token_Close(ctNew, 0, 0);
689 if (ct)
690 GWEN_Crypt_Token_Close(ct, 0, 0);
691
692 return j;
693 }
694
onServerKeysImported(AH_JOB_CHANGEKEYS * jd)695 int onServerKeysImported(AH_JOB_CHANGEKEYS *jd)
696 {
697 // serverkeys imported (knowing server-keys length is necessary for some key-types when created)
698 // create keys if required
699
700 char fmtBuff[256];
701 AH_HBCI *h = AH_Provider_GetHbci(jd->pro);
702 int res = 0;
703 const char *m = NULL;
704 const char *btn1 = NULL, *btn2 = NULL, *btn3 = NULL;
705 uint8_t ok = 0;
706
707 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): flags 0x%04X.", __FUNCTION__, jd->flags);
708 if (jd->flags & FJCK_CHKEY) {
709 //if(!jd->cryptKeyInfo || !GWEN_Crypt_Token_KeyInfo_GetKeyNumber(jd->cryptKeyInfo) || !jd->signKeyInfo || !GWEN_Crypt_Token_KeyInfo_GetKeyNumber(jd->signKeyInfo))
710 if (!tokenHasKeys(jd->ct, jd->ctx)) {
711 m = fmtStr(FB, "Creating new keys on %s '%s'.", jd->fm, jd->tokenName);
712 btn1 = "Abort";
713 btn2 = "OK";
714 ok = 2;
715 }
716 else {
717 #if 0
718 // TODO check keys are compatible with cryptmode
719 // if so, ...
720 {
721 m = fmtStr(FB, "Auf %s '%s' sind Schluessel vorhanden,\nsollen dennoch neue Schluessel erzeugt werden?", fmn, wantedTokenName);
722 btn1 = "Abort";
723 btn2 = "No";
724 btn3 = "Yes";
725 ok = 3;
726 }
727 else {
728 m = fmtStr(FB, "Auf %s '%s' vorhandene Schluessel koennen nicht verwendet werden,\nneue Schluessel werden erzeugt.",
729 fmn, wantedTokenName);
730 btn1 = "Abort";
731 btn2 = "OK";
732 ok = 2;
733 }
734 #else
735 m = fmtStr(FB, "Auf %s '%s' sind Schluessel vorhanden die verwendet werden koennen,\n"
736 "wenn sie zum gewuehlten Verschluesselungsverfahren passen.\n"
737 "Sollen neue Schluessel erzeugt werden?", jd->fm, jd->tokenName);
738 btn1 = "Abort";
739 btn2 = "No";
740 btn3 = "Yes";
741 ok = 3;
742 #endif
743 }
744 res = GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
745 m, I18N(btn1), I18N(btn2), btn3 ? I18N(btn3) : NULL, 0);
746 if (res == 1) {
747 res = -1;
748 *jd->canceled = 1;
749 }
750 else {
751 if (res == ok) {
752 res = 0;
753 DBG_INFO(AQHBCI_LOGDOMAIN, "creating keys...");
754 res = AH_Provider_CreateKeys(jd->pro, jd->uTmp, 1);
755 if (res)
756 res = onError(fmtStr(FB, "Could not create keys (%d).", res), -1);
757 DBG_INFO(AQHBCI_LOGDOMAIN, "creating keys done.");
758 }
759 else
760 res = 0;
761 }
762 }
763 else
764 res = -1;
765 if ((res == 0) &&
766 (getKeyInfo(h, jd->tokenType, jd->tokenName, jd->tokenCtxId, &jd->ct, &jd->ctx, &jd->cryptKeyInfo, &jd->signKeyInfo,
767 &jd->authKeyInfo)
768 || !jd->ct || !jd->ctx || !jd->cryptKeyInfo || !jd->signKeyInfo || !jd->authKeyInfo))
769 res = onError("Could not get key-info.", -1);
770
771 if (res == 0) {
772 #if 1
773 if (!(jd->flags & FJCK_CHPROFILE)) {
774 // set keyversion from current token + 1 on dest.-token
775 uint32_t kvV = jd->currentCryptKeyVersion ? (jd->currentCryptKeyVersion + 1) : 0;
776 uint32_t kvS = jd->currentSignKeyVersion ? (jd->currentSignKeyVersion + 1) : 0;
777 uint32_t kvA = jd->currentAuthKeyVersion ? (jd->currentAuthKeyVersion + 1) : 0;
778
779 DBG_NOTICE(AQHBCI_LOGDOMAIN, "set keyversions %ld -> %ld, %ld -> %ld, %ld -> %ld.",
780 (long)jd->currentCryptKeyVersion, (long)kvV, (long)jd->currentSignKeyVersion, (long)kvS,
781 (long)jd->currentAuthKeyVersion, (long)kvA);
782 if (kvV)
783 setKeyVersion((GWEN_CRYPT_TOKEN *)jd->ct, jd->ctx, jd->cryptKeyInfo, 'V', kvV);
784 if (kvS)
785 setKeyVersion((GWEN_CRYPT_TOKEN *)jd->ct, jd->ctx, jd->signKeyInfo, 'S', kvS);
786 if (!(jd->flags & FJCK_DSTFILE) && kvA)
787 setKeyVersion((GWEN_CRYPT_TOKEN *)jd->ct, jd->ctx, jd->authKeyInfo, 'A', kvA);
788 }
789 #endif
790 if (jd->flags & FJCK_CHKEY) {
791 if (!jd->signKeyInfo || !GWEN_Crypt_Token_KeyInfo_GetKeyNumber(jd->signKeyInfo)) {
792 DBG_INFO(AQHBCI_LOGDOMAIN, "Kein Signierschluessel.");
793 res = onError("Kein Signierschluessel auf dem Ziel-medium gefunden.", -1);
794 }
795 else {
796 int sc = GWEN_Crypt_Token_KeyInfo_GetSignCounter(jd->signKeyInfo);
797 DBG_INFO(AQHBCI_LOGDOMAIN, "%s(): sig counter %d.", __FUNCTION__, sc);
798 if (sc > 1) {
799 if (!(jd->flags & FJCK_DSTFILE))
800 res = onError("Der Sequenzzaehler kann nicht zurueckgesetzt werden.", -1);
801 else {
802 res = GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
803 "Der Sequenzzaehler wird zurueckgesetzt.", I18N("Abort"), I18N("OK"), NULL, 0);
804 if (res != 2)
805 res = -1;
806 else
807 res = 0;
808 }
809 if (res == 0) {
810 DBG_INFO(AQHBCI_LOGDOMAIN, "%s(): reset sig counter.", __FUNCTION__);
811 GWEN_Crypt_Token_KeyInfo_SetSignCounter((GWEN_CRYPT_TOKEN_KEYINFO *)jd->signKeyInfo, 1);
812 }
813 }
814 }
815 }
816 }
817
818 if (res == 0) {
819 if (getKeyInfo(h, jd->tokenType, jd->tokenName, jd->tokenCtxId, &jd->ct, &jd->ctx, &jd->cryptKeyInfo, &jd->signKeyInfo,
820 &jd->authKeyInfo)
821 || !jd->ct || !jd->ctx || !jd->cryptKeyInfo || !jd->signKeyInfo || !jd->authKeyInfo)
822 res = onError("Could not get key-info.", -1);
823 }
824
825 if ((res == 0) && !jd->ctx)
826 res = onError("Missing new ctx.", -1);
827
828 return res;
829 }
830
831 #define RSP_NOSRVRSP 1
832 #define RSP_WARN 2
833 #define RSP_ERR 3
834
parseResponse(AH_JOB * j)835 int8_t parseResponse(AH_JOB *j)
836 {
837 int8_t res = 0;
838 int rc = 0;
839 uint8_t gotResp = 0;
840 AH_JOB_CHANGEKEYS *jd = GWEN_INHERIT_GETDATA(AH_JOB, AH_JOB_CHANGEKEYS, j);
841 GWEN_DB_NODE *n = AH_Job_GetResponses(j);
842 if (AH_Job_GetStatus(j) != AH_JobStatusAnswered)
843 rc = -1;
844 assert(n);
845 jd->emsg = GWEN_Buffer_new(NULL, 2048, 0, 0);
846 n = GWEN_DB_GetFirstGroup(n);
847 while (n) {
848 //GWEN_DB_Dump(n, 0);
849 if (!strcmp(GWEN_DB_GroupName(n), "SegResult")) {
850 int mn = GWEN_DB_GetIntValue(n, "security/msgnum", 0, -1);
851 if (mn == 2) {
852 gotResp = 1;
853 if ((rc >= 0) && (rc < 9000)) {
854 rc = GWEN_DB_GetIntValue(n, "data/SegResult/result/resultcode", 0, -1);
855 if (rc == 3250) {
856 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): response %d tells us: no HKEND.", __FUNCTION__, rc);
857 res = 1;
858 rc = 0;
859 }
860 else {
861 GWEN_Buffer_AppendString(jd->emsg, GWEN_DB_GetCharValue(n, "data/SegResult/result/text", 0, "?"));
862 GWEN_Buffer_AppendString(jd->emsg, "\n");
863 }
864 }
865 DBG_NOTICE(AQHBCI_LOGDOMAIN, "result %d.", rc);
866 DBG_NOTICE(AQHBCI_LOGDOMAIN, "result '%s'.", GWEN_Buffer_GetStart(jd->emsg));
867 }
868 else {
869 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): #%d result %d '%s'.", __FUNCTION__,
870 GWEN_DB_GetIntValue(n, "security/msgnum", 0, -1),
871 GWEN_DB_GetIntValue(n, "data/SegResult/result/resultcode", 0, -1),
872 GWEN_DB_GetCharValue(n, "data/SegResult/result/text", 0, "?"));
873 if (GWEN_DB_GetIntValue(n, "data/SegResult/result/resultcode", 0, -1) >= 9000) {
874 rc = GWEN_DB_GetIntValue(n, "data/SegResult/result/resultcode", 0, -1);
875 GWEN_Buffer_AppendString(jd->emsg, GWEN_DB_GetCharValue(n, "data/SegResult/result/text", 0, "?"));
876 GWEN_Buffer_AppendString(jd->emsg, "\n");
877 }
878 }
879 }
880 n = GWEN_DB_GetNextGroup(n);
881 }
882 if (!gotResp)
883 jd->resp = RSP_NOSRVRSP;
884 else
885 jd->resp = (rc < 3000) ? 0 : (rc < 9000) ? RSP_WARN : RSP_ERR;
886 return res;
887 }
888
AH_Job_ChangeKeys_FreeData(void * bp,void * p)889 void GWENHYWFAR_CB GWENHYWFAR_CB AH_Job_ChangeKeys_FreeData(void *bp, void *p)
890 {
891 AH_JOB_CHANGEKEYS *jd = (AH_JOB_CHANGEKEYS *)p;
892 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): %p uTmp %p.", __FUNCTION__, jd, jd->uTmp);
893
894 if (jd->uTmp)
895 AB_User_free(jd->uTmp);
896 if (jd->tokenType)
897 free(jd->tokenType);
898 if (jd->tokenName)
899 free(jd->tokenName);
900 if (jd->emsg)
901 GWEN_Buffer_free(jd->emsg);
902
903 GWEN_FREE_OBJECT(jd);
904 }
905
AH_Job_ChangeKeys_NextMsg(AH_JOB * j)906 int AH_Job_ChangeKeys_NextMsg(AH_JOB *j)
907 {
908 int rv = 0;
909 int mn = -1;
910 unsigned int jmn = 0;
911 GWEN_DB_NODE *dbr = NULL;
912 AH_JOB_CHANGEKEYS *jd;
913 assert(j);
914 jmn = AH_Job_GetMsgNum(j);
915 dbr = AH_Job_GetResponses(j);
916 dbr = GWEN_DB_GetFirstGroup(dbr);
917 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): jmn %d.", __FUNCTION__, jmn);
918 while (dbr) {
919 //GWEN_DB_Dump(dbr, 0);
920 rv = AH_Job_CheckEncryption(j, dbr);
921 if (rv) {
922 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): AH_Job_CheckEncryption() failed (%d).", __FUNCTION__, rv);
923 return -1;
924 }
925 rv = AH_Job_CheckSignature(j, dbr);
926 if (rv) {
927 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): AH_Job_CheckSignature() failed (%d).", __FUNCTION__, rv);
928 return -1;
929 }
930 if (!strcasecmp(GWEN_DB_GroupName(dbr), "MsgTail")) {
931 mn = GWEN_DB_GetIntValue(dbr, "security/msgnum", 0, -1);
932 if (mn < 0) {
933 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s: find msgnum failed.", __FUNCTION__);
934 }
935 else if ((mn == 1) && (jmn == mn)) {
936 const GWEN_CRYPT_KEY *bk = NULL;
937 GWEN_CRYPT_KEY *bkCurrV = NULL, *bkCurrS = NULL;
938 jd = GWEN_INHERIT_GETDATA(AH_JOB, AH_JOB_CHANGEKEYS, j);
939 assert(jd);
940 // get actual serverkeys to restore later
941 bk = AH_User_GetBankPubCryptKey(jd->u);
942 if (bk)
943 bkCurrV = GWEN_Crypt_KeyRsa_dup(bk);
944 bk = AH_User_GetBankPubSignKey(jd->u);
945 if (bk)
946 bkCurrS = GWEN_Crypt_KeyRsa_dup(bk);
947 rv = AH_Job_CommitSystemData(j, 0);
948 if (rv != 0) {
949 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): AH_Job_CommitSystemData() failed(%d).", __FUNCTION__, rv);
950 }
951 else if (!GWEN_Crypt_Token_IsOpen(jd->ct) && (GWEN_Crypt_Token_Open(jd->ct, 0, 0) < 0))
952 rv = onError("GWEN_Crypt_Token_Open() failed.", -1);
953 else {
954 uint8_t i;
955 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Info, I18N("Serverkeys imported."));
956 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): serverkeys should be imported now.", __FUNCTION__);
957 // some cryptmodes need length of serverkeys
958 // AH_Provider_CreateKeys() reads the length from user-token,
959 // which is the temporary user with the new token,
960 // so store server-keys from actual user (the now imported) on the new token
961 //DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): ctx %p.", __FUNCTION__, jd->ctx);
962 jd->ctx = GWEN_Crypt_Token_GetContext(jd->ct, jd->tokenCtxId, 0);
963 //DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): -> ctx %p.", __FUNCTION__, jd->ctx);
964 for (i = 0; (rv == 0) && (i < 2); i++) {
965 const GWEN_CRYPT_TOKEN_KEYINFO *tmp = NULL;
966 uint8_t *m = NULL, *e = NULL;
967 uint32_t ml = 0, el = 0;
968 uint32_t id = 0;
969 bk = NULL;
970 switch (i) {
971 case 0:
972 bk = AH_User_GetBankPubCryptKey(jd->u);
973 id = GWEN_Crypt_Token_Context_GetEncipherKeyId(jd->ctx);
974 AH_User_SetBankPubCryptKey(jd->uTmp, (GWEN_CRYPT_KEY *)bk);
975 break;
976 case 1:
977 bk = AH_User_GetBankPubSignKey(jd->u);
978 id = GWEN_Crypt_Token_Context_GetVerifyKeyId(jd->ctx);
979 AH_User_SetBankPubSignKey(jd->uTmp, (GWEN_CRYPT_KEY *)bk);
980 break;
981 }
982
983 if (!bk) {
984 if (i == 0) {
985 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): get bankkey failed.", __FUNCTION__);
986 rv = -1;
987 }
988 else
989 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): bank has no signkey.", __FUNCTION__);
990 continue;
991 }
992
993 ml = GWEN_Crypt_Key_GetKeySize(bk);
994 el = 3;
995
996 if (ml) {
997 m = malloc(ml);
998 e = malloc(el);
999 GWEN_Crypt_KeyRsa_GetModulus(bk, m, &ml);
1000 GWEN_Crypt_KeyRsa_GetExponent(bk, e, &el);
1001 }
1002 tmp = GWEN_Crypt_Token_GetKeyInfo(jd->ct, id, 0, 0);
1003 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): k %ld m %ld %p e %ld %p.", __FUNCTION__, (long)id, (long)ml, m, (long)el, e);
1004 if (!tmp) {
1005 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): damn, get keyinfo '%c' failed.", __FUNCTION__, (i == 0) ? 'V' : 'S');
1006 rv = onError("GWEN_Crypt_Token_GetKeyInfo() failed.", -1);
1007 }
1008 if (rv == 0) {
1009 GWEN_CRYPT_TOKEN_KEYINFO *ki = GWEN_Crypt_Token_KeyInfo_dup(tmp);
1010 uint32_t flags = GWEN_Crypt_Token_KeyInfo_GetFlags(ki);
1011 GWEN_Crypt_Token_KeyInfo_SetFlags(ki,
1012 flags | GWEN_CRYPT_TOKEN_KEYFLAGS_HASMODULUS | GWEN_CRYPT_TOKEN_KEYFLAGS_HASEXPONENT);
1013 GWEN_Crypt_Token_KeyInfo_SetModulus(ki, m, ml);
1014 GWEN_Crypt_Token_KeyInfo_SetExponent(ki, e, el);
1015 GWEN_Crypt_Token_KeyInfo_SetKeySize(ki, ml);
1016 GWEN_Crypt_Token_KeyInfo_SetKeyNumber(ki, GWEN_Crypt_Key_GetKeyNumber(bk));
1017 GWEN_Crypt_Token_KeyInfo_SetKeyVersion(ki, GWEN_Crypt_Key_GetKeyVersion(bk));
1018 if (GWEN_Crypt_Token_SetKeyInfo(jd->ct, id, ki, 0)) {
1019 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): GWEN_Crypt_Token_SetKeyInfo() failed.", __FUNCTION__);
1020 rv = -1;
1021 }
1022 else
1023 ki = NULL;
1024 if (ki)
1025 GWEN_Crypt_Token_KeyInfo_free(ki);
1026 }
1027 if (m)
1028 free(m);
1029 if (e)
1030 free(e);
1031 }
1032 if (rv == 0) {
1033 rv = onServerKeysImported(jd);
1034 if (rv != 0)
1035 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): onServerKeysImported() failed.", __FUNCTION__);
1036 }
1037 // serverkeys set in job_commit() must restored
1038 if (bkCurrV) {
1039 AH_User_SetBankPubCryptKey(jd->u, bkCurrV);
1040 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): serverkey 'V' restored.", __FUNCTION__);
1041 GWEN_Crypt_Key_free(bkCurrV);
1042 }
1043 if (bkCurrS) {
1044 AH_User_SetBankPubSignKey(jd->u, bkCurrS);
1045 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): serverkey 'S' restored.", __FUNCTION__);
1046 GWEN_Crypt_Key_free(bkCurrS);
1047 }
1048 if (rv == 0) {
1049 uint8_t i;
1050
1051 // update segment-data
1052 GWEN_DB_NODE *args = AH_Job_GetArguments(j);
1053 assert(args);
1054 for (i = 0; (rv == 0) && (i < 3); i++) {
1055 GWEN_DB_NODE *db = NULL;
1056 const GWEN_CRYPT_TOKEN_KEYINFO *ki = NULL;
1057 const uint8_t *kd = NULL;
1058 uint32_t kdsz = 0;
1059 const char *kt = "?";
1060 int kn = 0, kv = 0;
1061
1062 switch (i) {
1063 case 0:
1064 kt = "V";
1065 ki = jd->cryptKeyInfo;
1066 db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "setcryptKey");
1067 break;
1068 case 1:
1069 kt = "S";
1070 ki = jd->signKeyInfo;
1071 db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "setsignKey");
1072 break;
1073 case 2:
1074 kt = "D";
1075 ki = jd->authKeyInfo;
1076 db = GWEN_DB_GetGroup(args, GWEN_DB_FLAGS_DEFAULT, "setauthKey");
1077 break;
1078 }
1079
1080 if (!ki) {
1081 if (i < 2) {
1082 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): get keyinfo '%s' failed.", __FUNCTION__, kt);
1083 rv = -1;
1084 }
1085 else
1086 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): token has no authkey.", __FUNCTION__);
1087 continue;
1088 }
1089
1090 kd = GWEN_Crypt_Token_KeyInfo_GetModulusData(ki);
1091 kdsz = GWEN_Crypt_Token_KeyInfo_GetModulusLen(ki);
1092 if (!kd || !kdsz) {
1093 DBG_ERROR(AQHBCI_LOGDOMAIN, "No modulus in '%s' key.", kt);
1094 rv = -1;
1095 break;
1096 }
1097 GWEN_DB_SetBinValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/modulus", kd, kdsz);
1098
1099 kd = GWEN_Crypt_Token_KeyInfo_GetExponentData(ki);
1100 kdsz = GWEN_Crypt_Token_KeyInfo_GetExponentLen(ki);
1101 if (!kd || !kdsz) {
1102 DBG_ERROR(AQHBCI_LOGDOMAIN, "No exponent in '%s' key.", kt);
1103 rv = -1;
1104 break;
1105 }
1106 GWEN_DB_SetBinValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/exponent", kd, kdsz);
1107
1108 kd = GWEN_Crypt_Token_KeyInfo_GetCertificateData(ki);
1109 kdsz = GWEN_Crypt_Token_KeyInfo_GetCertificateLen(ki);
1110 if (kd && kdsz) {
1111 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "cert/type", GWEN_Crypt_Token_KeyInfo_GetCertType(ki));
1112 GWEN_DB_SetBinValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "cert/cert", kd, kdsz);
1113 }
1114 else
1115 DBG_NOTICE(AQHBCI_LOGDOMAIN, "No cert for '%s' on token.", kt);
1116
1117 kn = GWEN_Crypt_Token_KeyInfo_GetKeyNumber(ki);
1118 kv = GWEN_Crypt_Token_KeyInfo_GetKeyVersion(ki);
1119 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/keynum", kn);
1120 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "key/keyversion", kv);
1121 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "keyName/keynum", kn);
1122 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "keyName/keyversion", kv);
1123 }
1124 }
1125 }
1126 }
1127 else if ((mn == 2) && (jmn == mn)) {
1128 int8_t resp = parseResponse(j);
1129 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s: resp %d, %s HKEND.", __FUNCTION__, resp, (resp == 1) ? "no" : "next");
1130 if (resp == 1) // since 5.99.25 no chance to prevent HKEND :-(
1131 return 0;
1132 }
1133 }
1134 dbr = GWEN_DB_GetNextGroup(dbr);
1135 }
1136 return (rv == 0) ? 1 : -1;
1137 }
1138
AH_Job_ChangeKeys_finish(AB_PROVIDER * pro,AH_JOB * job,int res)1139 int AH_Job_ChangeKeys_finish(AB_PROVIDER *pro, AH_JOB *job, int res)
1140 {
1141 AH_JOB_CHANGEKEYS *jd = NULL;
1142 AB_USER *u = NULL;
1143 AB_USER *uTmp = NULL;
1144 if (!job)
1145 return res;
1146 jd = GWEN_INHERIT_GETDATA(AH_JOB, AH_JOB_CHANGEKEYS, job);
1147 if (*jd->canceled) {
1148 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): user canceled.", __FUNCTION__);
1149 jd->resp = -1;
1150 }
1151 u = jd->u;
1152 uTmp = jd->uTmp;
1153
1154 res = -1;
1155 if (jd->resp >= 0) {
1156 char fmtBuff[1024];
1157 const char *m = NULL;
1158 const char *btn1 = I18N("Abort");
1159 const char *btn2 = I18N("Finish");
1160 if (jd->resp == RSP_NOSRVRSP) {
1161 GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: Error"),
1162 "Der Bankserver hat keine Antwort zur Schluesselaenderung gesendet.", I18N("OK"), NULL, NULL, 0);
1163 res = -1;
1164 }
1165 else {
1166 if ((jd->resp == RSP_WARN) || (jd->resp == RSP_ERR)) {
1167 m = strdup(fmtStr(FB, "Der Bankserver meldet %s:\n\n'%s'\n\n"
1168 "Es ist moeglich, dass der neue Schluessel dennoch angenommenn wurde.\n"
1169 "Neue Schluessel / neues Medium uebernehmen?", (jd->resp == RSP_ERR) ? "Fehler" : "Warnungen",
1170 GWEN_Buffer_GetStart(jd->emsg)));
1171 btn1 = I18N("No");
1172 btn2 = fmtStr(FB, "%s, %s", I18N("Yes"), I18N("finish"));
1173 }
1174 else {
1175 m = strdup(fmtStr(FB, "Die Uebermittlung der Schluessel ergab keinen Fehler,\n"
1176 "aus den Meldungen des Bankservers sollte eine Uebernahme ersichtlich sein:\n\n%s\nNeue Schluessel / neues Medium\n"
1177 "wird uebernommen.", GWEN_Buffer_GetStart(jd->emsg)));
1178 }
1179 if (GWEN_Gui_MessageBox(GWEN_GUI_MSG_FLAGS_TYPE_INFO, I18N("Change keys: confirm"),
1180 m, btn1, btn2, NULL, 0) == 2)
1181 res = 0;
1182 }
1183 if (m)
1184 free((char *)m);
1185 }
1186 DBG_NOTICE(AQHBCI_LOGDOMAIN, "%s(): %d/%d %p %p.", __FUNCTION__, jd->resp, res, u, uTmp);
1187 if (uTmp) {
1188 DBG_INFO(AQHBCI_LOGDOMAIN, "%s: tokenTypeFromToken '%s' tokenNameFromToken '%s' rdh %d cm %d ctx-id %d.", __FUNCTION__,
1189 AH_User_GetTokenType(uTmp), AH_User_GetTokenName(uTmp), AH_User_GetRdhType(uTmp),
1190 AH_User_GetCryptMode(uTmp), AH_User_GetTokenContextId(uTmp));
1191 if (res == 0) {
1192 if (AB_Provider_BeginExclUseUser(pro, u)) {
1193 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): AB_Provider_BeginExclUseUser() failed.", __FUNCTION__);
1194 res = -1;
1195 }
1196 else {
1197 AH_User_SetBankPubCryptKey(u, AH_User_GetBankPubCryptKey(uTmp));
1198 AH_User_SetBankPubSignKey(u, AH_User_GetBankPubSignKey(uTmp));
1199 AH_User_SetTokenType(u, AH_User_GetTokenType(uTmp));
1200 AH_User_SetTokenName(u, AH_User_GetTokenName(uTmp));
1201 AH_User_SetRdhType(u, AH_User_GetRdhType(uTmp));
1202 AH_User_SetCryptMode(u, AH_User_GetCryptMode(uTmp));
1203 AH_User_SetTokenContextId(u, AH_User_GetTokenContextId(uTmp));
1204 if (AB_Provider_EndExclUseUser(pro, u, 0)) {
1205 DBG_ERROR(AQHBCI_LOGDOMAIN, "%s(): AB_Provider_EndExclUseUser() failed.", __FUNCTION__);
1206 res = -1;
1207 }
1208 }
1209 }
1210 AB_Provider_DeleteUser(pro, AB_User_GetUniqueId(uTmp));
1211 }
1212
1213 return res;
1214 }
1215