Example #1
0
static int EBC_Provider_SignMessage_X001(AB_PROVIDER *pro,
					 EB_MSG *msg,
					 AB_USER *u,
					 xmlNodePtr node) {
  EBC_PROVIDER *dp;
  int rv;
  GWEN_CRYPT_TOKEN *ct;
  const GWEN_CRYPT_TOKEN_CONTEXT *ctx;
  const GWEN_CRYPT_TOKEN_KEYINFO *ki;
  uint32_t keyId;
  GWEN_BUFFER *hbuf;
  GWEN_BUFFER *bbuf;
  xmlNodePtr nodeX = NULL;
  xmlNodePtr nodeXX = NULL;
  xmlNodePtr nodeXXX = NULL;
  xmlNodePtr nodeXXXX = NULL;
  xmlNsPtr ns;

  assert(pro);
  dp=GWEN_INHERIT_GETDATA(AB_PROVIDER, EBC_PROVIDER, pro);
  assert(dp);

  /* get crypt token and context */
  rv=EBC_Provider_MountToken(pro, u, &ct, &ctx);
  if (rv<0) {
    DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  /* get key id */
  keyId=GWEN_Crypt_Token_Context_GetAuthSignKeyId(ctx);
  ki=GWEN_Crypt_Token_GetKeyInfo(ct,
				 keyId,
				 0xffffffff,
				 0);
  if (ki==NULL) {
    DBG_INFO(AQEBICS_LOGDOMAIN,
	     "Keyinfo %04x not found on crypt token [%s:%s]",
	     keyId,
	     GWEN_Crypt_Token_GetTypeName(ct),
	     GWEN_Crypt_Token_GetTokenName(ct));
    GWEN_Crypt_Token_Close(ct, 0, 0);
    return GWEN_ERROR_NOT_FOUND;
  }

  /* prepare signature nodes */
  ns=xmlSearchNs(EB_Msg_GetDoc(msg), node, BAD_CAST "ds");
  assert(ns);

  /* build hash */
  bbuf=GWEN_Buffer_new(0, 256, 0, 1);
  rv=EB_Msg_BuildHashSha1(msg, bbuf);
  if (rv) {
    DBG_ERROR(AQEBICS_LOGDOMAIN, "Could not build hash");
    GWEN_Buffer_free(bbuf);
    return rv;
  }

  /* base64 encode */
  hbuf=GWEN_Buffer_new(0, 256, 0, 1);
  rv=GWEN_Base64_Encode((const uint8_t*)GWEN_Buffer_GetStart(bbuf),
			GWEN_Buffer_GetUsedBytes(bbuf),
			hbuf, 0);
  if (rv<0) {
    DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
    GWEN_Buffer_free(hbuf);
    GWEN_Buffer_free(bbuf);
    return rv;
  }
  GWEN_Buffer_free(bbuf);

  /* create signature node */
  nodeX=xmlNewChild(node, ns, BAD_CAST "SignedInfo", NULL);
  nodeXX=xmlNewChild(nodeX, ns, BAD_CAST "CanonicalizationMethod", NULL);
  xmlNewProp(nodeXX,
	     BAD_CAST "Algorithm",
	     BAD_CAST "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
  nodeXX=xmlNewChild(nodeX, ns, BAD_CAST "SignatureMethod", NULL);
  xmlNewProp(nodeXX,
	     BAD_CAST "Algorithm",
	     BAD_CAST "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
  nodeXX=xmlNewChild(nodeX, ns, BAD_CAST "Reference", NULL);
  xmlNewProp(nodeXX,
	     BAD_CAST "URI",
	     BAD_CAST "#xpointer(//*[@authenticate='true'])");
  nodeXXX=xmlNewChild(nodeXX, ns, BAD_CAST "Transforms", NULL);
  nodeXXXX=xmlNewChild(nodeXXX, ns, BAD_CAST "Transform", NULL);
  xmlNewProp(nodeXXXX,
	     BAD_CAST "Algorithm",
	     BAD_CAST "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");

  nodeXXX=xmlNewChild(nodeXX, ns, BAD_CAST "DigestMethod", NULL);
  xmlNewProp(nodeXXX,
	     BAD_CAST "Algorithm",
	     BAD_CAST "http://www.w3.org/2000/09/xmldsig#sha1");

  /* store hash value */
  xmlNewTextChild(nodeXX, ns,
		  BAD_CAST "DigestValue",
		  BAD_CAST GWEN_Buffer_GetStart(hbuf));
  GWEN_Buffer_free(hbuf);

  /* build hash over SignedInfo */
  bbuf=GWEN_Buffer_new(0, 256, 0, 1);
  rv=EB_Xml_BuildNodeHashSha1(nodeX, "#xpointer(//*)", bbuf);
  if (rv<0) {
    DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
    GWEN_Buffer_free(bbuf);
    return rv;
  }

  /* sign hash */
  if (1) {
    GWEN_CRYPT_PADDALGO *algo;
    int ksize;
    uint32_t l;
    const uint8_t prefix[]={
      0x30, 0x21, 0x30, 0x09,
      0x06, 0x05, 0x2B, 0x0E,
      0x03, 0x02, 0x1A, 0x05,
      0x00, 0x04, 0x14};

    /* add prefix to hash of SignedInfo */
    hbuf=GWEN_Buffer_new(0, 256, 0, 1);
    ksize=GWEN_Crypt_Token_KeyInfo_GetKeySize(ki);
    GWEN_Buffer_AppendBytes(hbuf, (const char*)prefix, sizeof(prefix));
    GWEN_Buffer_AppendBuffer(hbuf, bbuf);
    GWEN_Buffer_Reset(bbuf);

    /* select padd algo */
    algo=GWEN_Crypt_PaddAlgo_new(GWEN_Crypt_PaddAlgoId_Pkcs1_1);
    GWEN_Crypt_PaddAlgo_SetPaddSize(algo, ksize);

    /* actually sign */
    GWEN_Buffer_AllocRoom(bbuf, ksize+16);
    l=GWEN_Buffer_GetMaxUnsegmentedWrite(bbuf);
    rv=GWEN_Crypt_Token_Sign(ct, keyId,
			     algo,
			     (const uint8_t*)GWEN_Buffer_GetStart(hbuf),
			     GWEN_Buffer_GetUsedBytes(hbuf),
			     (uint8_t*)GWEN_Buffer_GetPosPointer(bbuf),
			     &l,
			     NULL, /* ignore seq counter */
			     0);
    GWEN_Crypt_PaddAlgo_free(algo);
    if (rv<0) {
      DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
      GWEN_Buffer_free(bbuf);
      GWEN_Buffer_free(hbuf);
      return rv;
    }
    GWEN_Buffer_IncrementPos(bbuf, l);
    GWEN_Buffer_AdjustUsedBytes(bbuf);

    /* base 64 encode signature */
    GWEN_Buffer_Reset(hbuf);
    rv=GWEN_Base64_Encode((const uint8_t*)GWEN_Buffer_GetStart(bbuf),
			  GWEN_Buffer_GetUsedBytes(bbuf),
			  hbuf, 0);
    if (rv<0) {
      DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
      GWEN_Buffer_free(hbuf);
      GWEN_Buffer_free(bbuf);
      return rv;
    }
    GWEN_Buffer_free(bbuf);

    /* store signature */
    xmlNewTextChild(node, ns,
		    BAD_CAST "SignatureValue",
		    BAD_CAST GWEN_Buffer_GetStart(hbuf));
    GWEN_Buffer_free(hbuf);
  }

  return 0;
}
Example #2
0
int EBC_Provider_EuSign_A004(AB_PROVIDER *pro,
			     AB_USER *u,
			     const char *requestType,
			     const uint8_t *pMsg,
			     uint32_t lMsg,
			     GWEN_BUFFER *sbuf) {
  EBC_PROVIDER *dp;
  GWEN_MDIGEST *md;
  GWEN_BUFFER *hbuf;
  GWEN_BUFFER *ebuf;
  GWEN_CRYPT_TOKEN *ct;
  const GWEN_CRYPT_TOKEN_CONTEXT *ctx;
  const GWEN_CRYPT_TOKEN_KEYINFO *ki;
  uint32_t keyId;
  int ksize;
  uint32_t l;
  GWEN_CRYPT_PADDALGO *algo;
  EB_EU *eu;
  GWEN_TIME *ti;
  int rv;
  const char *userId;

  assert(pro);
  dp=GWEN_INHERIT_GETDATA(AB_PROVIDER, EBC_PROVIDER, pro);
  assert(dp);

  userId=AB_User_GetUserId(u);

  md=GWEN_MDigest_Rmd160_new();
  assert(md);
  rv=GWEN_MDigest_Begin(md);
  if (rv<0) {
    DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
    GWEN_MDigest_free(md);
    return rv;
  }
  rv=GWEN_MDigest_Update(md, pMsg, lMsg);
  if (rv<0) {
    DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
    GWEN_MDigest_free(md);
    return rv;
  }
  rv=GWEN_MDigest_End(md);
  if (rv<0) {
    DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
    GWEN_MDigest_free(md);
    return rv;
  }

  hbuf=GWEN_Buffer_new(0, GWEN_MDigest_GetDigestSize(md), 0, 1);
  GWEN_Buffer_AppendBytes(hbuf,
			  (const char*)GWEN_MDigest_GetDigestPtr(md),
			  GWEN_MDigest_GetDigestSize(md));
  GWEN_MDigest_free(md);

  /* get crypt token and context */
  rv=EBC_Provider_MountToken(pro, u, &ct, &ctx);
  if (rv<0) {
    DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  /* get key id */
  keyId=GWEN_Crypt_Token_Context_GetSignKeyId(ctx);
  ki=GWEN_Crypt_Token_GetKeyInfo(ct,
				 keyId,
				 0xffffffff,
				 0);
  if (ki==NULL) {
    DBG_INFO(AQEBICS_LOGDOMAIN,
	     "Keyinfo %04x not found on crypt token [%s:%s]",
	     keyId,
	     GWEN_Crypt_Token_GetTypeName(ct),
	     GWEN_Crypt_Token_GetTokenName(ct));
    GWEN_Crypt_Token_Close(ct, 0, 0);
    GWEN_Buffer_free(hbuf);
    return GWEN_ERROR_NOT_FOUND;
  }

  ksize=GWEN_Crypt_Token_KeyInfo_GetKeySize(ki);

  /* select padd algo */
  algo=GWEN_Crypt_PaddAlgo_new(GWEN_Crypt_PaddAlgoId_Iso9796_2);
  GWEN_Crypt_PaddAlgo_SetPaddSize(algo, ksize);

  /* actually sign */
  ebuf=GWEN_Buffer_new(0, ksize+16, 0, 1);
  l=GWEN_Buffer_GetMaxUnsegmentedWrite(ebuf);
  rv=GWEN_Crypt_Token_Sign(ct, keyId,
			   algo,
			   (const uint8_t*)GWEN_Buffer_GetStart(hbuf),
			   GWEN_Buffer_GetUsedBytes(hbuf),
			   (uint8_t*)GWEN_Buffer_GetPosPointer(ebuf),
			   &l,
			   NULL, /* ignore seq counter */
			   0);
  GWEN_Crypt_PaddAlgo_free(algo);
  if (rv<0) {
    DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
    GWEN_Buffer_free(ebuf);
    GWEN_Buffer_free(hbuf);
    return rv;
  }
  GWEN_Buffer_IncrementPos(ebuf, l);
  GWEN_Buffer_AdjustUsedBytes(ebuf);

  GWEN_Buffer_free(hbuf);

  /* assemble EU */
  eu=EB_Eu_new();
  EB_Eu_SetVersion(eu, "A004");
  EB_Eu_SetModLen(eu, ksize*8);
  EB_Eu_SetJobType(eu, requestType);
  EB_Eu_SetSignature(eu,
		     (const uint8_t*) GWEN_Buffer_GetStart(ebuf),
		     GWEN_Buffer_GetUsedBytes(ebuf));
  GWEN_Buffer_free(ebuf);
  ti=GWEN_CurrentTime();
  EB_Eu_SetCreationTime(eu, ti);
  EB_Eu_SetSignatureTime(eu, ti);
  GWEN_Time_free(ti);

  EB_Eu_SetUserId(eu, userId);

  /* store EU in given buffer */
  EB_Eu_toBuffer(eu, sbuf);
  EB_Eu_free(eu);

  return 0;
}
Example #3
0
int signWithNew(GWEN_DB_NODE *dbArgs, int argc, char **argv) {
  GWEN_DB_NODE *db;
  const char *ttype;
  const char *tname;
  GWEN_PLUGIN_MANAGER *pm;
  GWEN_PLUGIN *pl;
  GWEN_CRYPT_TOKEN *ct;
  unsigned int cid;
  int rv;
  const GWEN_ARGS args[]={
  {
    GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
    GWEN_ArgsType_Int,             /* type */
    "contextId",                  /* name */
    0,                            /* minnum */
    1,                            /* maxnum */
    "i",                          /* short option */
    "id",                         /* long option */
    "Context id (0 for any)",     /* short description */
    "Context id (0 for any)"      /* long description */
  },
  {
    GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
    GWEN_ArgsType_Char,            /* type */
    "tokenType",                  /* name */
    1,                            /* minnum */
    1,                            /* maxnum */
    "t",                          /* short option */
    "ttype",                    /* long option */
    "Specify the crypt token type",     /* short description */
    "Specify the crypt token type"      /* long description */
  },
  {
    GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
    GWEN_ArgsType_Char,            /* type */
    "tokenName",                  /* name */
    0,                            /* minnum */
    1,                            /* maxnum */
    "n",                          /* short option */
    "tname",                    /* long option */
    "Specify the crypt token name",     /* short description */
    "Specify the crypt token name"      /* long description */
  },
  {
    GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
    GWEN_ArgsType_Int,             /* type */
    "help",                       /* name */
    0,                            /* minnum */
    0,                            /* maxnum */
    "h",                          /* short option */
    "help",                       /* long option */
    "Show this help screen",      /* short description */
    "Show this help screen"       /* long description */
  }
  };

  db=GWEN_DB_GetGroup(dbArgs, GWEN_DB_FLAGS_DEFAULT, "local");
  rv=GWEN_Args_Check(argc, argv, 1,
                     GWEN_ARGS_MODE_ALLOW_FREEPARAM,
                     args,
                     db);
  if (rv==GWEN_ARGS_RESULT_ERROR) {
    fprintf(stderr, "ERROR: Could not parse arguments\n");
    return 1;
  }
  else if (rv==GWEN_ARGS_RESULT_HELP) {
    GWEN_BUFFER *ubuf;

    ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
    if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
      fprintf(stderr, "ERROR: Could not create help string\n");
      return 1;
    }
    fprintf(stderr, "%s\n", GWEN_Buffer_GetStart(ubuf));
    GWEN_Buffer_free(ubuf);
    return 0;
  }

  cid=GWEN_DB_GetIntValue(db, "contextId", 0, 0);

  ttype=GWEN_DB_GetCharValue(db, "tokenType", 0, 0);
  assert(ttype);

  tname=GWEN_DB_GetCharValue(db, "tokenName", 0, 0);

  /* get crypt token */
  pm=GWEN_PluginManager_FindPluginManager("ct");
  if (pm==0) {
    DBG_ERROR(0, "Plugin manager not found");
    return 3;
  }

  pl=GWEN_PluginManager_GetPlugin(pm, ttype);
  if (pl==0) {
    DBG_ERROR(0, "Plugin not found");
    return 3;
  }
  DBG_INFO(0, "Plugin found");

  ct=GWEN_Crypt_Token_Plugin_CreateToken(pl, tname);
  if (ct==0) {
    DBG_ERROR(0, "Could not create crypt token");
    return 3;
  }

  if (GWEN_DB_GetIntValue(dbArgs, "forcePin", 0, 0))
    GWEN_Crypt_Token_AddModes(ct, GWEN_CRYPT_TOKEN_MODE_FORCE_PIN_ENTRY);

  /* open crypt token for use */
  rv=GWEN_Crypt_Token_Open(ct, 0, 0);
  if (rv) {
    DBG_ERROR(0, "Could not open token");
    return 3;
  }
  else {
    uint8_t clearText[96]={
      0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
      0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
      0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
      0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
      0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
      0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
      0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
      0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
      0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
      0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
      0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
      0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60
    };
    uint8_t signature[256];
    uint32_t signLen;
    GWEN_CRYPT_PADDALGO *algo;

    algo=GWEN_Crypt_PaddAlgo_new(GWEN_Crypt_PaddAlgoId_None);
    signLen=sizeof(signature);
    rv=GWEN_Crypt_Token_Sign(ct,
			     0x01, /* local sign key */
			     algo,
			     clearText,
                             96,
			     signature,
			     &signLen,
			     NULL,
			     0);
    if (rv) {
      DBG_ERROR(0, "Could not sign data (%d)", rv);
      return 3;
    }

    fprintf(stderr, "Signature is:\n");
    GWEN_Text_DumpString((const char*) signature, signLen, stderr, 2);

    rv=GWEN_Crypt_Token_Verify(ct, 0x01,
			       algo,
			       clearText,
			       96,
			       signature,
			       signLen,
			       0,
			       0);
    if (rv) {
      DBG_ERROR(0, "Could not verify data (%d)", rv);
      return 3;
    }
    fprintf(stderr, "Signature is ok.\n");

  }

  /* close crypt token */
  rv=GWEN_Crypt_Token_Close(ct, 0, 0);
  if (rv) {
    DBG_ERROR(0, "Could not close token");
    return 3;
  }

  return 0;
}
Example #4
0
int EBC_Provider_EuSign_A005(AB_PROVIDER *pro,
                             AB_USER *u,
                             const char *requestType,
                             const uint8_t *pMsg,
                             uint32_t lMsg,
                             GWEN_BUFFER *sbuf)
{
  EBC_PROVIDER *dp;
  GWEN_BUFFER *xbuf;
  GWEN_BUFFER *hbuf;
  GWEN_CRYPT_TOKEN *ct;
  const GWEN_CRYPT_TOKEN_CONTEXT *ctx;
  const GWEN_CRYPT_TOKEN_KEYINFO *ki;
  uint32_t keyId;
  int ksize;
  uint32_t l;
  GWEN_CRYPT_PADDALGO *algo;
  int rv;
  int numPaddBytes=0;
  const uint8_t digestInfo[]= {
    0x30, 0x31, 0x30, 0x0d,
    0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
    0x05, 0x00,
    0x04, 0x20
  };

  assert(pro);
  dp=GWEN_INHERIT_GETDATA(AB_PROVIDER, EBC_PROVIDER, pro);
  assert(dp);

  /* get crypt token and context */
  rv=EBC_Provider_MountToken(pro, u, &ct, &ctx);
  if (rv<0) {
    DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  /* get key id */
  keyId=GWEN_Crypt_Token_Context_GetSignKeyId(ctx);
  ki=GWEN_Crypt_Token_GetKeyInfo(ct,
                                 keyId,
                                 0xffffffff,
                                 0);
  if (ki==NULL) {
    DBG_INFO(AQEBICS_LOGDOMAIN,
             "Keyinfo %04x not found on crypt token [%s:%s]",
             keyId,
             GWEN_Crypt_Token_GetTypeName(ct),
             GWEN_Crypt_Token_GetTokenName(ct));
    GWEN_Crypt_Token_Close(ct, 0, 0);
    return GWEN_ERROR_NOT_FOUND;
  }

  xbuf=GWEN_Buffer_new(0, 40, 0, 1);
  EBC_Provider_Sha256(pMsg, lMsg, xbuf);

  /* add digestInfo to hash of SignedInfo */
  hbuf=GWEN_Buffer_new(0, 256, 0, 1);
  ksize=GWEN_Crypt_Token_KeyInfo_GetKeySize(ki);

  GWEN_Buffer_AppendByte(hbuf, 0x01); /* block type */

  numPaddBytes=ksize-3-sizeof(digestInfo)-GWEN_Buffer_GetUsedBytes(xbuf);
  if (numPaddBytes<1) {
    DBG_ERROR(AQEBICS_LOGDOMAIN, "Invalid number of padd bytes, key too small (%d)", numPaddBytes);
    GWEN_Buffer_free(xbuf);
    GWEN_Buffer_free(hbuf);
    return GWEN_ERROR_INTERNAL;
  }
  GWEN_Buffer_FillWithBytes(hbuf, 0xff, numPaddBytes);

  GWEN_Buffer_AppendByte(hbuf, 0x01); /* separator */

  GWEN_Buffer_AppendBytes(hbuf, (const char *)digestInfo, sizeof(digestInfo)); /* digest info */
  GWEN_Buffer_AppendBytes(hbuf, GWEN_Buffer_GetStart(xbuf), GWEN_Buffer_GetUsedBytes(xbuf)); /* hash */
  GWEN_Buffer_free(xbuf);

  /* select padd algo */
  algo=GWEN_Crypt_PaddAlgo_new(GWEN_Crypt_PaddAlgoId_None);
  GWEN_Crypt_PaddAlgo_SetPaddSize(algo, ksize);

  /* actually sign */
  GWEN_Buffer_AllocRoom(sbuf, ksize+16);
  l=GWEN_Buffer_GetMaxUnsegmentedWrite(sbuf);
  rv=GWEN_Crypt_Token_Sign(ct, keyId,
                           algo,
                           (const uint8_t *)GWEN_Buffer_GetStart(hbuf),
                           GWEN_Buffer_GetUsedBytes(hbuf),
                           (uint8_t *)GWEN_Buffer_GetPosPointer(sbuf),
                           &l,
                           NULL, /* ignore seq counter */
                           0);
  GWEN_Crypt_PaddAlgo_free(algo);
  if (rv<0) {
    DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
    GWEN_Buffer_free(hbuf);
    return rv;
  }
  GWEN_Buffer_IncrementPos(sbuf, l);
  GWEN_Buffer_AdjustUsedBytes(sbuf);

  GWEN_Buffer_free(hbuf);

  return 0;
}
Example #5
0
int AH_Msg_SignRdh2(AH_MSG *hmsg,
                    AB_USER *su,
		    GWEN_BUFFER *rawBuf,
		    const char *signer) {
  AH_HBCI *h;
  GWEN_XMLNODE *node;
  GWEN_DB_NODE *cfg;
  GWEN_BUFFER *sigbuf;
  GWEN_BUFFER *hbuf;
  unsigned int l;
  int rv;
  char ctrlref[15];
  const char *p;
  GWEN_MSGENGINE *e;
  uint32_t uFlags;
  GWEN_CRYPT_TOKEN *ct;
  const GWEN_CRYPT_TOKEN_CONTEXT *ctx;
  const GWEN_CRYPT_TOKEN_KEYINFO *ki;
  uint32_t keyId;
  uint32_t gid;

  assert(hmsg);
  h=AH_Dialog_GetHbci(hmsg->dialog);
  assert(h);
  e=AH_Dialog_GetMsgEngine(hmsg->dialog);
  assert(e);
  GWEN_MsgEngine_SetMode(e, "rdh");

  gid=0;

  uFlags=AH_User_GetFlags(su);

  /* get crypt token of signer */
  rv=AB_Banking_GetCryptToken(AH_HBCI_GetBankingApi(h),
			   AH_User_GetTokenType(su),
			   AH_User_GetTokenName(su),
			   &ct);
  if (rv) {
    DBG_INFO(AQHBCI_LOGDOMAIN,
	     "Could not get crypt token for user \"%s\" (%d)",
	     AB_User_GetUserId(su), rv);
    return rv;
  }

  /* open CryptToken if necessary */
  if (!GWEN_Crypt_Token_IsOpen(ct)) {
    GWEN_Crypt_Token_AddModes(ct, GWEN_CRYPT_TOKEN_MODE_DIRECT_SIGN);
    rv=GWEN_Crypt_Token_Open(ct, 0, gid);
    if (rv) {
      DBG_INFO(AQHBCI_LOGDOMAIN,
	       "Could not open crypt token for user \"%s\" (%d)",
	       AB_User_GetUserId(su), rv);
      return rv;
    }
  }

  /* get context and key info */
  ctx=GWEN_Crypt_Token_GetContext(ct,
				  AH_User_GetTokenContextId(su),
				  gid);
  if (ctx==NULL) {
    DBG_INFO(AQHBCI_LOGDOMAIN,
	     "Context %d not found on crypt token [%s:%s]",
	     AH_User_GetTokenContextId(su),
	     GWEN_Crypt_Token_GetTypeName(ct),
	     GWEN_Crypt_Token_GetTokenName(ct));
    return GWEN_ERROR_NOT_FOUND;
  }

  keyId=GWEN_Crypt_Token_Context_GetSignKeyId(ctx);
  ki=GWEN_Crypt_Token_GetKeyInfo(ct,
                                 keyId,
				 0xffffffff,
				 gid);
  if (ki==NULL) {
    DBG_INFO(AQHBCI_LOGDOMAIN,
	     "Keyinfo %04x not found on crypt token [%s:%s]",
	     keyId,
	     GWEN_Crypt_Token_GetTypeName(ct),
	     GWEN_Crypt_Token_GetTokenName(ct));
    return GWEN_ERROR_NOT_FOUND;
  }

  node=GWEN_MsgEngine_FindNodeByPropertyStrictProto(e,
						    "SEG",
						    "id",
						    0,
						    "SigHead");
  if (!node) {
    DBG_INFO(AQHBCI_LOGDOMAIN, "Segment \"SigHead\" not found");
    return GWEN_ERROR_INTERNAL;
  }

  /* prepare config for segment */
  cfg=GWEN_DB_Group_new("sighead");
  rv=AH_MsgRdh_PrepareCryptoSeg2(hmsg, su, ki, cfg, 0, 1);
  if (rv) {
    DBG_INFO(AQHBCI_LOGDOMAIN, "here (%d)", rv);
    GWEN_DB_Group_free(cfg);
    return rv;
  }

  /* set expected signer */
  if (!(uFlags & AH_USER_FLAGS_BANK_DOESNT_SIGN)) {
    const char *remoteId;

    remoteId=AH_User_GetPeerId(su);
    if (!remoteId || *remoteId==0)
      remoteId=AB_User_GetUserId(su);
    assert(remoteId);
    assert(*remoteId);

    DBG_DEBUG(AQHBCI_LOGDOMAIN,
	      "Expecting \"%s\" to sign the response",
	      remoteId);
    AH_Msg_SetExpectedSigner(hmsg, remoteId);
  }

  /* store system id */
  if (hmsg->noSysId) {
    GWEN_DB_SetCharValue(cfg, GWEN_DB_FLAGS_DEFAULT,
			 "SecDetails/SecId", "0");
  }
  else {
    p=AH_User_GetSystemId(su);
    if (p==NULL)
      p=GWEN_Crypt_Token_Context_GetSystemId(ctx);
    if (p)
      GWEN_DB_SetCharValue(cfg, GWEN_DB_FLAGS_DEFAULT,
			   "SecDetails/SecId", p);
    else {
      GWEN_DB_SetCharValue(cfg, GWEN_DB_FLAGS_DEFAULT,
			   "SecDetails/SecId", "0");
    }
  }

  /* retrieve control reference for sigtail (to be used later) */
  p=GWEN_DB_GetCharValue(cfg, "ctrlref", 0, "");
  if (strlen(p)>=sizeof(ctrlref)) {
    DBG_INFO(AQHBCI_LOGDOMAIN, "Control reference too long (14 bytes maximum)");
    GWEN_DB_Group_free(cfg);
    return -1;
  }
  strcpy(ctrlref, p);

  /* create SigHead */
  hbuf=GWEN_Buffer_new(0, 128+GWEN_Buffer_GetUsedBytes(rawBuf), 0, 1);
  GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT,
                      "head/seq", hmsg->firstSegment-1);
  GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT,
		      "signseq",
                      GWEN_Crypt_Token_KeyInfo_GetSignCounter(ki));

  /* create signature head segment */
  rv=GWEN_MsgEngine_CreateMessageFromNode(e, node, hbuf, cfg);
  GWEN_DB_Group_free(cfg);
  cfg=0;
  if (rv) {
    DBG_INFO(AQHBCI_LOGDOMAIN, "Could not create SigHead");
    GWEN_Buffer_free(hbuf);
    return rv;
  }

  /* remember size of sighead for now */
  l=GWEN_Buffer_GetUsedBytes(hbuf);

  /* add raw data to to-sign data buffer */
  GWEN_Buffer_AppendBuffer(hbuf, rawBuf);

  /* sign message */
  sigbuf=GWEN_Buffer_new(0, 512, 0, 1);
  if (1) {
    uint32_t signLen;
    GWEN_CRYPT_PADDALGO *algo;
    GWEN_MDIGEST *md;
    uint32_t seq;

    /* hash sighead + data */
    md=GWEN_MDigest_Rmd160_new();
    rv=GWEN_MDigest_Begin(md);
    if (rv==0)
      rv=GWEN_MDigest_Update(md,
			     (uint8_t*)GWEN_Buffer_GetStart(hbuf),
			     GWEN_Buffer_GetUsedBytes(hbuf));
    if (rv==0)
      rv=GWEN_MDigest_End(md);
    if (rv<0) {
      DBG_ERROR(AQHBCI_LOGDOMAIN, "Hash error (%d)", rv);
      GWEN_MDigest_free(md);
      GWEN_Buffer_free(sigbuf);
      GWEN_Buffer_free(hbuf);
      return rv;
    }

    /* sign hash */
    algo=GWEN_Crypt_PaddAlgo_new(GWEN_Crypt_PaddAlgoId_Iso9796_2);
    GWEN_Crypt_PaddAlgo_SetPaddSize(algo, GWEN_Crypt_Token_KeyInfo_GetKeySize(ki));
    signLen=GWEN_Buffer_GetMaxUnsegmentedWrite(sigbuf);
    rv=GWEN_Crypt_Token_Sign(ct, keyId,
			     algo,
			     GWEN_MDigest_GetDigestPtr(md),
			     GWEN_MDigest_GetDigestSize(md),
			     (uint8_t*)GWEN_Buffer_GetPosPointer(sigbuf),
			     &signLen,
			     &seq,
			     gid);
    GWEN_Crypt_PaddAlgo_free(algo);
    GWEN_MDigest_free(md);
    if (rv) {
      DBG_ERROR(AQHBCI_LOGDOMAIN,
		"Could not sign data with medium of user \"%s\" (%d)",
		AB_User_GetUserId(su), rv);
      GWEN_Buffer_free(sigbuf);
      GWEN_Buffer_free(hbuf);
      return rv;
    }
    GWEN_Buffer_IncrementPos(sigbuf, signLen);
    GWEN_Buffer_AdjustUsedBytes(sigbuf);
  }
  DBG_DEBUG(AQHBCI_LOGDOMAIN, "Signing done");

  /* insert new SigHead at beginning of message buffer */
  DBG_DEBUG(AQHBCI_LOGDOMAIN, "Inserting signature head");
  GWEN_Buffer_Rewind(hmsg->buffer);
  GWEN_Buffer_InsertBytes(hmsg->buffer, GWEN_Buffer_GetStart(hbuf), l);

  /* create sigtail */
  DBG_DEBUG(AQHBCI_LOGDOMAIN, "Completing signature tail");
  cfg=GWEN_DB_Group_new("sigtail");
  GWEN_Buffer_Reset(hbuf);
  GWEN_DB_SetIntValue(cfg, GWEN_DB_FLAGS_DEFAULT,
                      "head/seq", hmsg->lastSegment+1);
  /* store to DB */
  GWEN_DB_SetBinValue(cfg, GWEN_DB_FLAGS_DEFAULT,
                      "signature",
                      GWEN_Buffer_GetStart(sigbuf),
                      GWEN_Buffer_GetUsedBytes(sigbuf));
  GWEN_Buffer_free(sigbuf);
  GWEN_DB_SetCharValue(cfg, GWEN_DB_FLAGS_DEFAULT,
		       "ctrlref", ctrlref);

  /* get node */
  node=GWEN_MsgEngine_FindNodeByPropertyStrictProto(e,
						    "SEG",
						    "id",
						    0,
						    "SigTail");
  if (!node) {
    DBG_INFO(AQHBCI_LOGDOMAIN, "Segment \"SigTail\"not found");
    GWEN_Buffer_free(hbuf);
    GWEN_DB_Group_free(cfg);
    return -1;
  }
  rv=GWEN_MsgEngine_CreateMessageFromNode(e, node, hbuf, cfg);
  if (rv) {
    DBG_INFO(AQHBCI_LOGDOMAIN, "Could not create SigTail");
    GWEN_Buffer_free(hbuf);
    GWEN_DB_Group_free(cfg);
    return -1;
  }

  /* append sigtail */
  DBG_DEBUG(AQHBCI_LOGDOMAIN, "Appending signature tail");
  if (GWEN_Buffer_AppendBuffer(hmsg->buffer, hbuf)) {
    DBG_INFO(AQHBCI_LOGDOMAIN, "here");
    GWEN_Buffer_free(hbuf);
    GWEN_DB_Group_free(cfg);
    return -1;
  }
  DBG_DEBUG(AQHBCI_LOGDOMAIN, "Appending signature tail: done");

  GWEN_Buffer_free(hbuf);
  GWEN_DB_Group_free(cfg);

  /* adjust segment numbers (for next signature and message tail */
  hmsg->firstSegment--;
  hmsg->lastSegment++;

  return 0;
}