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