1 /***************************************************************************
2     begin       : Thu Jan 31 2019
3     copyright   : (C) 2019 by Martin Preuss
4     email       : martin@libchipcard.de
5 
6  ***************************************************************************
7  *          Please see toplevel file COPYING for license details           *
8  ***************************************************************************/
9 
10 
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14 
15 
16 #include "jobgetkeys_p.h"
17 
18 #include "aqhbci/joblayer/job_crypt.h"
19 
20 
21 GWEN_INHERIT(AH_JOB, AH_JOB_GETKEYS);
22 
23 
24 
25 
AH_Job_GetKeys_new(AB_PROVIDER * pro,AB_USER * u)26 AH_JOB *AH_Job_GetKeys_new(AB_PROVIDER *pro, AB_USER *u)
27 {
28   AH_JOB *j;
29   AH_JOB_GETKEYS *jd;
30   GWEN_DB_NODE *args;
31   int version;
32 
33   assert(u);
34   j=AH_Job_new("JobGetKeys", pro, u, 0, 0);
35   if (!j) {
36     DBG_ERROR(AQHBCI_LOGDOMAIN, "JobGetKeys not supported, should not happen");
37     return NULL;
38   }
39 
40   /* create data for inheriting class */
41   GWEN_NEW_OBJECT(AH_JOB_GETKEYS, jd);
42   GWEN_INHERIT_SETDATA(AH_JOB, AH_JOB_GETKEYS,
43                        j, jd, AH_Job_GetKeys_FreeData);
44 
45   /* overwrite virtual function */
46   AH_Job_SetProcessFn(j, AH_Job_GetKeys_Process);
47 
48   /* set args */
49   args=AH_Job_GetArguments(j);
50   assert(args);
51   GWEN_DB_SetCharValue(args, GWEN_DB_FLAGS_OVERWRITE_VARS, "open/ident/customerId", "9999999999");
52   GWEN_DB_SetIntValue(args, GWEN_DB_FLAGS_OVERWRITE_VARS, "open/ident/status", 0);
53   GWEN_DB_SetCharValue(args, GWEN_DB_FLAGS_OVERWRITE_VARS, "open/ident/systemId", "0");
54 
55   version=AH_User_GetRdhType(u);
56   if (version==0)
57     version=1;
58   switch (AH_User_GetCryptMode(u)) {
59   case AH_CryptMode_Rdh:
60     GWEN_DB_SetCharValue(args, GWEN_DB_FLAGS_OVERWRITE_VARS, "open/cryptKey/secprofile/code", "RDH");
61     GWEN_DB_SetCharValue(args, GWEN_DB_FLAGS_OVERWRITE_VARS, "open/signKey/secprofile/code", "RDH");
62     break;
63 
64   case AH_CryptMode_Rah:
65     GWEN_DB_SetCharValue(args, GWEN_DB_FLAGS_OVERWRITE_VARS, "open/cryptKey/secprofile/code", "RAH");
66     GWEN_DB_SetCharValue(args, GWEN_DB_FLAGS_OVERWRITE_VARS, "open/signKey/secprofile/code", "RAH");
67     break;
68   default:
69     break;
70   }
71 
72   GWEN_DB_SetIntValue(args, GWEN_DB_FLAGS_OVERWRITE_VARS, "open/cryptKey/secprofile/version", version);
73   GWEN_DB_SetIntValue(args, GWEN_DB_FLAGS_OVERWRITE_VARS, "open/signKey/secprofile/version", version);
74 
75   return j;
76 }
77 
78 
79 
AH_Job_GetKeys_FreeData(void * bp,void * p)80 void GWENHYWFAR_CB GWENHYWFAR_CB AH_Job_GetKeys_FreeData(void *bp, void *p)
81 {
82   AH_JOB_GETKEYS *jd;
83 
84   jd=(AH_JOB_GETKEYS *) p;
85 
86   GWEN_Crypt_Token_KeyInfo_free(jd->signKeyInfo);
87   GWEN_Crypt_Token_KeyInfo_free(jd->cryptKeyInfo);
88   GWEN_Crypt_Token_KeyInfo_free(jd->authKeyInfo);
89   free(jd->peerId);
90   GWEN_FREE_OBJECT(jd);
91 }
92 
93 
94 
AH_Job_GetKeys_Process(AH_JOB * j,AB_IMEXPORTER_CONTEXT * ctx)95 int AH_Job_GetKeys_Process(AH_JOB *j, AB_IMEXPORTER_CONTEXT *ctx)
96 {
97   AH_HBCI *h;
98   AH_JOB_GETKEYS *jd;
99   AB_USER *u;
100   GWEN_DB_NODE *dbResponses;
101   GWEN_DB_NODE *dbCurr;
102   int rv;
103   int haveKey;
104   GWEN_CRYPT_TOKEN *ct;
105   const GWEN_CRYPT_TOKEN_CONTEXT *cctx;
106 
107   assert(j);
108   jd=GWEN_INHERIT_GETDATA(AH_JOB, AH_JOB_GETKEYS, j);
109   assert(jd);
110 
111   h=AH_Job_GetHbci(j);
112   u=AH_Job_GetUser(j);
113   rv=AB_Banking_GetCryptToken(AH_HBCI_GetBankingApi(h),
114                               AH_User_GetTokenType(u),
115                               AH_User_GetTokenName(u),
116                               &ct);
117   if (rv) {
118     DBG_INFO(AQHBCI_LOGDOMAIN, "here (%d)", rv);
119     return rv;
120   }
121 
122   cctx=GWEN_Crypt_Token_GetContext(ct, AH_User_GetTokenContextId(u), 0);
123   if (cctx==NULL) {
124     DBG_ERROR(AQHBCI_LOGDOMAIN,
125               "CT context %d not found",
126               AH_User_GetTokenContextId(u));
127     return GWEN_ERROR_NOT_FOUND;
128   }
129 
130   dbResponses=AH_Job_GetResponses(j);
131   assert(dbResponses);
132 
133   /* search for "GetKeyResponse" */
134   haveKey=0;
135   dbCurr=GWEN_DB_GetFirstGroup(dbResponses);
136   while (dbCurr) {
137     GWEN_DB_NODE *dbKeyResponse;
138     int rv;
139 
140     rv=AH_Job_CheckEncryption(j, dbCurr);
141     if (rv) {
142       DBG_INFO(AQHBCI_LOGDOMAIN, "Compromised security (encryption)");
143       return rv;
144     }
145     rv=AH_Job_CheckSignature(j, dbCurr);
146     if (rv) {
147       DBG_INFO(AQHBCI_LOGDOMAIN, "Compromised security (signature)");
148       return rv;
149     }
150 
151     dbKeyResponse=GWEN_DB_GetGroup(dbCurr, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "data/GetKeyResponse");
152     if (dbKeyResponse) {
153       unsigned int bs;
154       const uint8_t *p;
155 
156       DBG_DEBUG(AQHBCI_LOGDOMAIN, "Got this key response:");
157       if (GWEN_Logger_GetLevel(AQHBCI_LOGDOMAIN)>=GWEN_LoggerLevel_Debug)
158         GWEN_DB_Dump(dbKeyResponse, 2);
159 
160       p=GWEN_DB_GetBinValue(dbKeyResponse, "key/modulus", 0, 0, 0, &bs);
161       if (!p || !bs) {
162         DBG_ERROR(AQHBCI_LOGDOMAIN, "No modulus");
163         return GWEN_ERROR_BAD_DATA;
164       }
165       else {
166         const uint8_t defaultExpo[3]= {0x01, 0x00, 0x01};
167         const char *s;
168         uint32_t keyId;
169         GWEN_CRYPT_TOKEN_KEYINFO *ki;
170         int keySize;
171         uint32_t flags=0;
172 
173         /* skip zero bytes if any */
174         while (bs && *p==0) {
175           p++;
176           bs--;
177         }
178 
179         /* calculate key size in bytes */
180         if (bs<=96)
181           keySize=96;
182         else {
183           keySize=bs;
184         }
185 
186         s=GWEN_DB_GetCharValue(dbKeyResponse, "keyname/keytype", 0, "V");
187         if (strcasecmp(s, "V")==0)
188           keyId=GWEN_Crypt_Token_Context_GetEncipherKeyId(cctx);
189         else if (strcasecmp(s, "S")==0)
190           keyId=GWEN_Crypt_Token_Context_GetVerifyKeyId(cctx);
191         else
192           keyId=GWEN_Crypt_Token_Context_GetAuthVerifyKeyId(cctx);
193 
194         ki=GWEN_Crypt_Token_KeyInfo_new(keyId, GWEN_Crypt_CryptAlgoId_Rsa, keySize);
195 
196         GWEN_Crypt_Token_KeyInfo_SetModulus(ki, p, bs);
197         GWEN_Crypt_Token_KeyInfo_SetExponent(ki, defaultExpo, sizeof(defaultExpo));
198 
199         flags|=
200           GWEN_CRYPT_TOKEN_KEYFLAGS_HASACTIONFLAGS |
201           GWEN_CRYPT_TOKEN_KEYFLAGS_HASMODULUS |
202           GWEN_CRYPT_TOKEN_KEYFLAGS_HASEXPONENT |
203           GWEN_CRYPT_TOKEN_KEYFLAGS_HASKEYVERSION |
204           GWEN_CRYPT_TOKEN_KEYFLAGS_HASKEYNUMBER;
205         if (strcasecmp(s, "V")==0) {
206           flags|=GWEN_CRYPT_TOKEN_KEYFLAGS_CANENCIPHER;
207           jd->cryptKeyInfo=ki;
208           s=GWEN_DB_GetCharValue(dbKeyResponse, "keyname/userId", 0, NULL);
209           free(jd->peerId);
210           if (s)
211             jd->peerId=strdup(s);
212           else
213             jd->peerId=NULL;
214         }
215         else if (strcasecmp(s, "S")==0) {
216           flags|=GWEN_CRYPT_TOKEN_KEYFLAGS_CANVERIFY;
217           jd->signKeyInfo=ki;
218         }
219         else {
220           flags|=GWEN_CRYPT_TOKEN_KEYFLAGS_CANVERIFY;
221           jd->authKeyInfo=ki;
222         }
223         GWEN_Crypt_Token_KeyInfo_SetFlags(ki, flags);
224         GWEN_Crypt_Token_KeyInfo_SetKeyNumber(ki, GWEN_DB_GetIntValue(dbKeyResponse, "keyname/keynum", 0, 0));
225         GWEN_Crypt_Token_KeyInfo_SetKeyVersion(ki, GWEN_DB_GetIntValue(dbKeyResponse, "keyname/keyversion", 0, 0));
226       }
227       haveKey++;
228     } /* if we have one */
229     dbCurr=GWEN_DB_GetNextGroup(dbCurr);
230   } /* while */
231 
232   if (haveKey==0) {
233     DBG_INFO(AQHBCI_LOGDOMAIN, "No server keys found");
234     AH_Job_SetStatus(j, AH_JobStatusError);
235     return GWEN_ERROR_NO_DATA;
236   }
237   return 0;
238 }
239 
240 
241 
AH_Job_GetKeys_GetSignKeyInfo(const AH_JOB * j)242 GWEN_CRYPT_TOKEN_KEYINFO *AH_Job_GetKeys_GetSignKeyInfo(const AH_JOB *j)
243 {
244   AH_JOB_GETKEYS *jd;
245 
246   assert(j);
247   jd=GWEN_INHERIT_GETDATA(AH_JOB, AH_JOB_GETKEYS, j);
248   assert(jd);
249 
250   return jd->signKeyInfo;
251 }
252 
253 
254 
AH_Job_GetKeys_GetCryptKeyInfo(const AH_JOB * j)255 GWEN_CRYPT_TOKEN_KEYINFO *AH_Job_GetKeys_GetCryptKeyInfo(const AH_JOB *j)
256 {
257   AH_JOB_GETKEYS *jd;
258 
259   assert(j);
260   jd=GWEN_INHERIT_GETDATA(AH_JOB, AH_JOB_GETKEYS, j);
261   assert(jd);
262 
263   return jd->cryptKeyInfo;
264 }
265 
266 
267 
AH_Job_GetKeys_GetAuthKeyInfo(const AH_JOB * j)268 GWEN_CRYPT_TOKEN_KEYINFO *AH_Job_GetKeys_GetAuthKeyInfo(const AH_JOB *j)
269 {
270   AH_JOB_GETKEYS *jd;
271 
272   assert(j);
273   jd=GWEN_INHERIT_GETDATA(AH_JOB, AH_JOB_GETKEYS, j);
274   assert(jd);
275 
276   return jd->authKeyInfo;
277 }
278 
279 
280 
AH_Job_GetKeys_GetPeerId(const AH_JOB * j)281 const char *AH_Job_GetKeys_GetPeerId(const AH_JOB *j)
282 {
283   AH_JOB_GETKEYS *jd;
284 
285   assert(j);
286   jd=GWEN_INHERIT_GETDATA(AH_JOB, AH_JOB_GETKEYS, j);
287   assert(jd);
288 
289   return jd->peerId;
290 }
291 
292 
293