1 /***************************************************************************
2 begin : Sun Oct 27 2019
3 copyright : (C) 2019 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * This file is part of the project "AqBanking". *
8 * Please see toplevel file COPYING of that project for license details. *
9 ***************************************************************************/
10
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14
15 #include "session/hbci/s_sign_hbci.h"
16 #include "session/s_decode.h"
17 #include "session/cryptparams.h"
18 #include "parser/parser.h"
19
20 #include <gwenhywfar/misc.h>
21 #include <gwenhywfar/debug.h>
22 #include <gwenhywfar/text.h>
23 #include <gwenhywfar/mdigest.h>
24 #include <gwenhywfar/paddalgo.h>
25
26 #include <time.h>
27
28
29
30 /* ------------------------------------------------------------------------------------------------
31 * forward declarations
32 * ------------------------------------------------------------------------------------------------
33 */
34
35 static AQFINTS_SEGMENT *_createSigHead(AQFINTS_SESSION *sess, const AQFINTS_CRYPTPARAMS *cryptParams,
36 int segNum, const AQFINTS_KEYDESCR *keyDescr, const char *ctrlRef);
37 static AQFINTS_SEGMENT *_createSigTail(AQFINTS_SESSION *sess,
38 const AQFINTS_CRYPTPARAMS *cryptParams,
39 int segNum,
40 const AQFINTS_KEYDESCR *keyDescr,
41 const char *ctrlRef,
42 const uint8_t *ptrSignature, uint32_t lenSignature);
43
44
45 static int _createCtrlRef(char *ptrBuf, size_t lenBuf);
46 static int _prepareSignSeg(AQFINTS_SESSION *sess,
47 const AQFINTS_CRYPTPARAMS *cryptParams,
48 const AQFINTS_KEYDESCR *keyDescr,
49 const char *ctrlRef,
50 GWEN_DB_NODE *cfg);
51
52 static int _signSegments(AQFINTS_SESSION *sess,
53 const AQFINTS_CRYPTPARAMS *cryptParams,
54 const AQFINTS_KEYDESCR *keyDescr,
55 AQFINTS_SEGMENT *segSigHead,
56 AQFINTS_SEGMENT *segFirstToSign,
57 AQFINTS_SEGMENT *segLastToSign,
58 GWEN_BUFFER *sigBuf);
59
60
61
62 /* ------------------------------------------------------------------------------------------------
63 * implementations
64 * ------------------------------------------------------------------------------------------------
65 */
66
67
68
AQFINTS_Session_SignSegmentHbci(AQFINTS_SESSION * sess,AQFINTS_MESSAGE * message,AQFINTS_KEYDESCR * keyDescr,AQFINTS_SEGMENT * segFirstToSign,AQFINTS_SEGMENT * segLastToSign,int sigHeadNum,int sigTailNum)69 int AQFINTS_Session_SignSegmentHbci(AQFINTS_SESSION *sess,
70 AQFINTS_MESSAGE *message,
71 AQFINTS_KEYDESCR *keyDescr,
72 AQFINTS_SEGMENT *segFirstToSign,
73 AQFINTS_SEGMENT *segLastToSign,
74 int sigHeadNum,
75 int sigTailNum)
76 {
77 int rv;
78 AQFINTS_SEGMENT_LIST *segmentList;
79 char ctrlref[15];
80 AQFINTS_SEGMENT *segment;
81 const char *securityProfileName;
82 int securityProfileVersion;
83 const AQFINTS_CRYPTPARAMS *cryptParams;
84 GWEN_BUFFER *sigBuf;
85
86 securityProfileName=AQFINTS_KeyDescr_GetSecurityProfileName(keyDescr);
87 securityProfileVersion=AQFINTS_KeyDescr_GetSecurityProfileVersion(keyDescr);
88
89 /* hack for hibiscus */
90 if (securityProfileVersion==0) {
91 if (securityProfileName && strcasecmp(securityProfileName, "RDH")==0)
92 securityProfileVersion=10;
93 }
94
95 cryptParams=AQFINTS_CryptParams_GetParamsForSecurityProfile(securityProfileName, securityProfileVersion);
96 if (cryptParams==NULL) {
97 DBG_ERROR(AQFINTS_LOGDOMAIN, "No crypt params for [%s:%d]", securityProfileName?securityProfileName:"<empty>",
98 securityProfileVersion);
99 return GWEN_ERROR_INVALID;
100 }
101
102 segmentList=AQFINTS_Message_GetSegmentList(message);
103
104 rv=_createCtrlRef(ctrlref, sizeof(ctrlref));
105 if (rv<0) {
106 DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
107 return rv;
108 }
109
110 rv=AQFINTS_Session_FilloutKeyname(sess, keyDescr, AQFINTS_SESSION_CRYPTOP_SIGN);
111 if (rv<0) {
112 DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
113 return rv;
114 }
115
116 segment=_createSigHead(sess, cryptParams, sigHeadNum, keyDescr, ctrlref);
117 if (segment==NULL) {
118 DBG_INFO(AQFINTS_LOGDOMAIN, "here");
119 return GWEN_ERROR_GENERIC;
120 }
121 AQFINTS_Segment_List_Insert(segment, segmentList);
122
123 sigBuf=GWEN_Buffer_new(0, 256, 0, 1);
124 rv=_signSegments(sess, cryptParams, keyDescr, segment, segFirstToSign, segLastToSign, sigBuf);
125 if (rv<0) {
126 DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
127 GWEN_Buffer_free(sigBuf);
128 return rv;
129 }
130
131 segment=_createSigTail(sess, cryptParams, sigTailNum, keyDescr, ctrlref,
132 (const uint8_t *) GWEN_Buffer_GetStart(sigBuf),
133 GWEN_Buffer_GetUsedBytes(sigBuf));
134 if (segment==NULL) {
135 DBG_INFO(AQFINTS_LOGDOMAIN, "here");
136 GWEN_Buffer_free(sigBuf);
137 return GWEN_ERROR_GENERIC;
138 }
139 GWEN_Buffer_free(sigBuf);
140 AQFINTS_Segment_List_Add(segment, segmentList);
141
142 return 0;
143 }
144
145
146
_signSegments(AQFINTS_SESSION * sess,const AQFINTS_CRYPTPARAMS * cryptParams,const AQFINTS_KEYDESCR * keyDescr,AQFINTS_SEGMENT * segSigHead,AQFINTS_SEGMENT * segFirstToSign,AQFINTS_SEGMENT * segLastToSign,GWEN_BUFFER * sigBuf)147 int _signSegments(AQFINTS_SESSION *sess,
148 const AQFINTS_CRYPTPARAMS *cryptParams,
149 const AQFINTS_KEYDESCR *keyDescr,
150 AQFINTS_SEGMENT *segSigHead,
151 AQFINTS_SEGMENT *segFirstToSign,
152 AQFINTS_SEGMENT *segLastToSign,
153 GWEN_BUFFER *sigBuf)
154 {
155 uint32_t signLen;
156 int rv;
157 GWEN_BUFFER *hashSrcBuffer;
158
159 hashSrcBuffer=GWEN_Buffer_new(0, 1024, 0, 1);
160 rv=AQFINTS_Session_SampleDataToHash(segSigHead, segFirstToSign, segLastToSign, hashSrcBuffer);
161 if (rv<0) {
162 DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
163 return rv;
164 }
165
166 signLen=GWEN_Buffer_GetMaxUnsegmentedWrite(sigBuf);
167 GWEN_Buffer_AllocRoom(sigBuf, 256);
168 rv=AQFINTS_Session_Sign(sess, keyDescr, cryptParams,
169 (const uint8_t *) GWEN_Buffer_GetStart(hashSrcBuffer),
170 GWEN_Buffer_GetUsedBytes(hashSrcBuffer),
171 (uint8_t *)GWEN_Buffer_GetStart(sigBuf),
172 &signLen);
173 if (rv<0) {
174 DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
175 GWEN_Buffer_free(hashSrcBuffer);
176 return rv;
177 }
178 GWEN_Buffer_free(hashSrcBuffer);
179 GWEN_Buffer_IncrementPos(sigBuf, signLen);
180 GWEN_Buffer_AdjustUsedBytes(sigBuf);
181
182 return 0;
183 }
184
185
186
187
188
_createSigHead(AQFINTS_SESSION * sess,const AQFINTS_CRYPTPARAMS * cryptParams,int segNum,const AQFINTS_KEYDESCR * keyDescr,const char * ctrlRef)189 AQFINTS_SEGMENT *_createSigHead(AQFINTS_SESSION *sess,
190 const AQFINTS_CRYPTPARAMS *cryptParams,
191 int segNum, const AQFINTS_KEYDESCR *keyDescr, const char *ctrlRef)
192 {
193 GWEN_DB_NODE *dbSegment;
194 AQFINTS_PARSER *parser;
195 int hbciVersion;
196 AQFINTS_SEGMENT *defSegment;
197 AQFINTS_SEGMENT *segment;
198 int rv;
199
200 parser=AQFINTS_Session_GetParser(sess);
201 hbciVersion=AQFINTS_Session_GetHbciVersion(sess);
202
203 /* HNSHA */
204 defSegment=AQFINTS_Parser_FindSegmentHighestVersionForProto(parser, "HNSHK", hbciVersion);
205 if (defSegment==NULL) {
206 DBG_ERROR(AQFINTS_LOGDOMAIN, "No matching definition segment found for HNSHK (proto=%d)", hbciVersion);
207 return NULL;
208 }
209
210 segment=AQFINTS_Segment_new();
211 AQFINTS_Segment_copy(segment, defSegment);
212 AQFINTS_Segment_SetSegmentNumber(segment, segNum);
213 dbSegment=GWEN_DB_Group_new("sigHead");
214 AQFINTS_Segment_SetDbData(segment, dbSegment);
215
216 rv=_prepareSignSeg(sess, cryptParams, keyDescr, ctrlRef, dbSegment);
217 if (rv<0) {
218 DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
219 AQFINTS_Segment_free(segment);
220 return NULL;
221 }
222
223 rv=AQFINTS_Session_WriteSegment(sess, segment);
224 if (rv<0) {
225 DBG_INFO(0, "here (%d)", rv);
226 AQFINTS_Segment_free(segment);
227 }
228
229 return segment;
230 }
231
232
233
_createSigTail(AQFINTS_SESSION * sess,const AQFINTS_CRYPTPARAMS * cryptParams,int segNum,const AQFINTS_KEYDESCR * keyDescr,const char * ctrlRef,const uint8_t * ptrSignature,uint32_t lenSignature)234 AQFINTS_SEGMENT *_createSigTail(AQFINTS_SESSION *sess,
235 const AQFINTS_CRYPTPARAMS *cryptParams,
236 int segNum,
237 const AQFINTS_KEYDESCR *keyDescr,
238 const char *ctrlRef,
239 const uint8_t *ptrSignature, uint32_t lenSignature)
240 {
241 GWEN_DB_NODE *dbSegment;
242 AQFINTS_PARSER *parser;
243 int hbciVersion;
244 AQFINTS_SEGMENT *defSegment;
245 AQFINTS_SEGMENT *segment;
246 int rv;
247 const char *s;
248
249 parser=AQFINTS_Session_GetParser(sess);
250 hbciVersion=AQFINTS_Session_GetHbciVersion(sess);
251
252 /* HNSHA */
253 defSegment=AQFINTS_Parser_FindSegmentHighestVersionForProto(parser, "HNSHA", hbciVersion);
254 if (defSegment==NULL) {
255 DBG_ERROR(AQFINTS_LOGDOMAIN, "No matching definition segment found for HNSHA (proto=%d)", hbciVersion);
256 return NULL;
257 }
258
259 segment=AQFINTS_Segment_new();
260 AQFINTS_Segment_copy(segment, defSegment);
261 AQFINTS_Segment_SetSegmentNumber(segment, segNum);
262
263 dbSegment=GWEN_DB_Group_new("sigTail");
264 AQFINTS_Segment_SetDbData(segment, dbSegment);
265
266 GWEN_DB_SetCharValue(dbSegment, GWEN_DB_FLAGS_DEFAULT, "ctrlref", ctrlRef);
267
268 if (ptrSignature && lenSignature)
269 GWEN_DB_SetBinValue(dbSegment, GWEN_DB_FLAGS_DEFAULT, "signature", ptrSignature, lenSignature);
270
271 s=AQFINTS_KeyDescr_GetPin(keyDescr);
272 if (s && *s)
273 GWEN_DB_SetCharValue(dbSegment, GWEN_DB_FLAGS_DEFAULT, "pin", s);
274
275 s=AQFINTS_KeyDescr_GetTan(keyDescr);
276 if (s && *s)
277 GWEN_DB_SetCharValue(dbSegment, GWEN_DB_FLAGS_DEFAULT, "tan", s);
278
279 rv=AQFINTS_Session_WriteSegment(sess, segment);
280 if (rv<0) {
281 DBG_INFO(AQFINTS_LOGDOMAIN, "here (%d)", rv);
282 AQFINTS_Segment_free(segment);
283 }
284
285 return segment;
286 }
287
288
289
290
291
_createCtrlRef(char * ptrBuf,size_t lenBuf)292 int _createCtrlRef(char *ptrBuf, size_t lenBuf)
293 {
294
295 struct tm *lt;
296 time_t tt;
297
298 tt=time(0);
299 lt=localtime(&tt);
300
301 if (!strftime(ptrBuf, lenBuf, "%Y%m%d%H%M%S", lt)) {
302 DBG_INFO(AQFINTS_LOGDOMAIN, "CtrlRef string too long");
303 return GWEN_ERROR_INTERNAL;
304 }
305
306 return 0;
307 }
308
309
310
_prepareSignSeg(AQFINTS_SESSION * sess,const AQFINTS_CRYPTPARAMS * cryptParams,const AQFINTS_KEYDESCR * keyDescr,const char * ctrlRef,GWEN_DB_NODE * cfg)311 int _prepareSignSeg(AQFINTS_SESSION *sess,
312 const AQFINTS_CRYPTPARAMS *cryptParams,
313 const AQFINTS_KEYDESCR *keyDescr,
314 const char *ctrlRef,
315 GWEN_DB_NODE *cfg)
316 {
317 char sdate[9];
318 char stime[7];
319 struct tm *lt;
320 time_t tt;
321 const char *s;
322 const char *securityProfileName;
323 int securityProfileVersion;
324
325 /* some preparations */
326 tt=time(0);
327 lt=localtime(&tt);
328
329 /* create date */
330 if (!strftime(sdate, sizeof(sdate), "%Y%m%d", lt)) {
331 DBG_INFO(AQFINTS_LOGDOMAIN, "Date string too long");
332 return GWEN_ERROR_INTERNAL;
333 }
334 /* create time */
335 if (!strftime(stime, sizeof(stime), "%H%M%S", lt)) {
336 DBG_INFO(AQFINTS_LOGDOMAIN, "Date string too long");
337 return GWEN_ERROR_INTERNAL;
338 }
339
340 /* store info */
341
342 /* security profile */
343 securityProfileName=AQFINTS_KeyDescr_GetSecurityProfileName(keyDescr);
344 securityProfileVersion=AQFINTS_KeyDescr_GetSecurityProfileVersion(keyDescr);
345
346 /* hack for hibiscus */
347 if (securityProfileVersion==0) {
348 if (securityProfileName && strcasecmp(securityProfileName, "RDH")==0)
349 securityProfileVersion=10;
350 }
351
352 GWEN_DB_SetCharValue(cfg, GWEN_DB_FLAGS_DEFAULT, "secProfile/code", securityProfileName);
353 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "secProfile/version", securityProfileVersion);
354
355 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "function", 2); /* sign with digital signature key */
356 GWEN_DB_SetCharValue(cfg, GWEN_DB_FLAGS_DEFAULT, "ctrlref", ctrlRef);
357 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "area", 1);
358 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "role", 1);
359
360 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "SecDetails/id",
361 AQFINTS_Session_GetIsServer(sess)?2:1); /* 1 client, 2=server */
362
363 s=AQFINTS_KeyDescr_GetSystemId(keyDescr);
364 if (s && *s)
365 GWEN_DB_SetCharValue(cfg, GWEN_DB_FLAGS_DEFAULT, "SecDetails/secId", s);
366 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "signseq", AQFINTS_KeyDescr_GetSignatureCounter(keyDescr));
367
368 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "SecStamp/stampCode", 1);
369 GWEN_DB_SetCharValue(cfg, GWEN_DB_FLAGS_DEFAULT, "SecStamp/date", sdate);
370 GWEN_DB_SetCharValue(cfg, GWEN_DB_FLAGS_DEFAULT, "SecStamp/time", stime);
371
372 /* hashAlgo */
373 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "hashAlgo/purpose", 1);
374 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "hashAlgo/algo", AQFINTS_CryptParams_GetHashAlgoSign(cryptParams));
375 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "hashAlgo/pname", 1);
376
377 /* signAlgo */
378 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "signAlgo/purpose", 6);
379 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "signAlgo/algo", AQFINTS_CryptParams_GetSignAlgo(cryptParams));
380 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "signAlgo/mode", AQFINTS_CryptParams_GetOpModeSign(cryptParams));
381
382 /* keyname */
383 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "key/country", AQFINTS_KeyDescr_GetCountry(keyDescr));
384 GWEN_DB_SetCharValue(cfg, GWEN_DB_FLAGS_DEFAULT, "key/bankcode", AQFINTS_KeyDescr_GetBankCode(keyDescr));
385 GWEN_DB_SetCharValue(cfg, GWEN_DB_FLAGS_DEFAULT, "key/userid", AQFINTS_KeyDescr_GetUserId(keyDescr));
386 GWEN_DB_SetCharValue(cfg, GWEN_DB_FLAGS_DEFAULT, "key/keytype", AQFINTS_KeyDescr_GetKeyType(keyDescr));
387 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "key/keynum", AQFINTS_KeyDescr_GetKeyNumber(keyDescr));
388 GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT, "key/keyversion", AQFINTS_KeyDescr_GetKeyVersion(keyDescr));
389
390 /* TODO: add certificate data */
391
392 return 0;
393 }
394
395
396
397