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