gwenhywfar/src/cryptmsg/cryptmgr.c @ dfefcc0f
b2e1935d | martin | /***************************************************************************
|
|
begin : Mon Dec 01 2008
|
|||
copyright : (C) 2008 by Martin Preuss
|
|||
email : martin@libchipcard.de
|
|||
***************************************************************************
|
|||
* Please see toplevel file COPYING for license details *
|
|||
***************************************************************************/
|
|||
#ifdef HAVE_CONFIG_H
|
|||
# include <config.h>
|
|||
#endif
|
|||
07ca863d | martin | #define DISABLE_DEBUGLOG
|
|
b2e1935d | martin | ||
#include "cryptmgr_p.h"
|
|||
#include "i18n_l.h"
|
|||
#include <gwenhywfar/misc.h>
|
|||
#include <gwenhywfar/debug.h>
|
|||
#include <gwenhywfar/gwentime.h>
|
|||
81b7bc73 | martin | #include <gwenhywfar/crypthead.h>
|
|
#include <gwenhywfar/sighead.h>
|
|||
#include <gwenhywfar/sigtail.h>
|
|||
b2e1935d | martin | #include <gwenhywfar/tag16.h>
|
|
#include <gwenhywfar/cryptkeysym.h>
|
|||
#include <gwenhywfar/padd.h>
|
|||
GWEN_INHERIT_FUNCTIONS(GWEN_CRYPTMGR)
|
|||
GWEN_CRYPTMGR *GWEN_CryptMgr_new() {
|
|||
GWEN_CRYPTMGR *cm;
|
|||
GWEN_NEW_OBJECT(GWEN_CRYPTMGR, cm);
|
|||
GWEN_INHERIT_INIT(GWEN_CRYPTMGR, cm);
|
|||
return cm;
|
|||
}
|
|||
void GWEN_CryptMgr_free(GWEN_CRYPTMGR *cm) {
|
|||
if (cm) {
|
|||
GWEN_INHERIT_FINI(GWEN_CRYPTMGR, cm);
|
|||
free(cm->localKeyName);
|
|||
free(cm->peerKeyName);
|
|||
GWEN_FREE_OBJECT(cm);
|
|||
}
|
|||
}
|
|||
const char *GWEN_CryptMgr_GetLocalKeyName(const GWEN_CRYPTMGR *cm) {
|
|||
assert(cm);
|
|||
return cm->localKeyName;
|
|||
}
|
|||
void GWEN_CryptMgr_SetLocalKeyName(GWEN_CRYPTMGR *cm, const char *s) {
|
|||
assert(cm);
|
|||
free(cm->localKeyName);
|
|||
if (s) cm->localKeyName=strdup(s);
|
|||
else cm->localKeyName=NULL;
|
|||
}
|
|||
int GWEN_CryptMgr_GetLocalKeyNumber(const GWEN_CRYPTMGR *cm) {
|
|||
assert(cm);
|
|||
return cm->localKeyNumber;
|
|||
}
|
|||
void GWEN_CryptMgr_SetLocalKeyNumber(GWEN_CRYPTMGR *cm, int i) {
|
|||
assert(cm);
|
|||
cm->localKeyNumber=i;
|
|||
}
|
|||
int GWEN_CryptMgr_GetLocalKeyVersion(const GWEN_CRYPTMGR *cm) {
|
|||
assert(cm);
|
|||
return cm->localKeyVersion;
|
|||
}
|
|||
void GWEN_CryptMgr_SetLocalKeyVersion(GWEN_CRYPTMGR *cm, int i) {
|
|||
assert(cm);
|
|||
cm->localKeyVersion=i;
|
|||
}
|
|||
const char *GWEN_CryptMgr_GetPeerKeyName(const GWEN_CRYPTMGR *cm) {
|
|||
assert(cm);
|
|||
return cm->peerKeyName;
|
|||
}
|
|||
void GWEN_CryptMgr_SetPeerKeyName(GWEN_CRYPTMGR *cm, const char *s) {
|
|||
assert(cm);
|
|||
free(cm->peerKeyName);
|
|||
if (s) cm->peerKeyName=strdup(s);
|
|||
else cm->peerKeyName=NULL;
|
|||
}
|
|||
int GWEN_CryptMgr_GetPeerKeyNumber(const GWEN_CRYPTMGR *cm) {
|
|||
assert(cm);
|
|||
return cm->peerKeyNumber;
|
|||
}
|
|||
void GWEN_CryptMgr_SetPeerKeyNumber(GWEN_CRYPTMGR *cm, int i) {
|
|||
assert(cm);
|
|||
cm->peerKeyNumber=i;
|
|||
}
|
|||
int GWEN_CryptMgr_GetPeerKeyVersion(const GWEN_CRYPTMGR *cm) {
|
|||
assert(cm);
|
|||
return cm->peerKeyVersion;
|
|||
}
|
|||
void GWEN_CryptMgr_SetPeerKeyVersion(GWEN_CRYPTMGR *cm, int i) {
|
|||
assert(cm);
|
|||
cm->peerKeyVersion=i;
|
|||
}
|
|||
int GWEN_CryptMgr_GetCryptProfile(const GWEN_CRYPTMGR *cm) {
|
|||
assert(cm);
|
|||
return cm->cryptProfile;
|
|||
}
|
|||
void GWEN_CryptMgr_SetCryptProfile(GWEN_CRYPTMGR *cm, int i) {
|
|||
assert(cm);
|
|||
cm->cryptProfile=i;
|
|||
}
|
|||
int GWEN_CryptMgr_GetSignatureProfile(const GWEN_CRYPTMGR *cm) {
|
|||
assert(cm);
|
|||
return cm->signatureProfile;
|
|||
}
|
|||
void GWEN_CryptMgr_SetSignatureProfile(GWEN_CRYPTMGR *cm, int i) {
|
|||
assert(cm);
|
|||
cm->signatureProfile=i;
|
|||
}
|
|||
int GWEN_CryptMgr_SignData(GWEN_CRYPTMGR *cm, const uint8_t *pData, uint32_t lData, GWEN_BUFFER *dbuf) {
|
|||
assert(cm);
|
|||
if (cm->signDataFn)
|
|||
return cm->signDataFn(cm, pData, lData, dbuf);
|
|||
else
|
|||
return GWEN_ERROR_NOT_IMPLEMENTED;
|
|||
}
|
|||
int GWEN_CryptMgr_EncryptKey(GWEN_CRYPTMGR *cm, const uint8_t *pData, uint32_t lData, GWEN_BUFFER *dbuf) {
|
|||
assert(cm);
|
|||
if (cm->encryptKeyFn)
|
|||
return cm->encryptKeyFn(cm, pData, lData, dbuf);
|
|||
else
|
|||
return GWEN_ERROR_NOT_IMPLEMENTED;
|
|||
}
|
|||
int GWEN_CryptMgr_VerifyData(GWEN_CRYPTMGR *cm,
|
|||
const uint8_t *pData, uint32_t lData,
|
|||
const uint8_t *pSignature, uint32_t lSignature) {
|
|||
assert(cm);
|
|||
if (cm->verifyDataFn)
|
|||
return cm->verifyDataFn(cm, pData, lData, pSignature, lSignature);
|
|||
else
|
|||
return GWEN_ERROR_NOT_IMPLEMENTED;
|
|||
}
|
|||
int GWEN_CryptMgr_DecryptKey(GWEN_CRYPTMGR *cm, const uint8_t *pData, uint32_t lData, GWEN_BUFFER *dbuf) {
|
|||
assert(cm);
|
|||
if (cm->decryptKeyFn)
|
|||
return cm->decryptKeyFn(cm, pData, lData, dbuf);
|
|||
else
|
|||
return GWEN_ERROR_NOT_IMPLEMENTED;
|
|||
}
|
|||
eca2062e | martin | GWEN_CRYPTMGR_SIGNDATA_FN GWEN_CryptMgr_SetSignDataFn(GWEN_CRYPTMGR *cm,
|
|
GWEN_CRYPTMGR_SIGNDATA_FN f) {
|
|||
GWEN_CRYPTMGR_SIGNDATA_FN of;
|
|||
b2e1935d | martin | assert(cm);
|
|
eca2062e | martin | of=cm->signDataFn;
|
|
b2e1935d | martin | cm->signDataFn=f;
|
|
eca2062e | martin | return of;
|
|
b2e1935d | martin | }
|
|
eca2062e | martin | GWEN_CRYPTMGR_VERIFYDATA_FN GWEN_CryptMgr_SetVerifyDataFn(GWEN_CRYPTMGR *cm,
|
|
GWEN_CRYPTMGR_VERIFYDATA_FN f) {
|
|||
GWEN_CRYPTMGR_VERIFYDATA_FN of;
|
|||
b2e1935d | martin | assert(cm);
|
|
eca2062e | martin | of=cm->verifyDataFn;
|
|
b2e1935d | martin | cm->verifyDataFn=f;
|
|
eca2062e | martin | return of;
|
|
b2e1935d | martin | }
|
|
eca2062e | martin | GWEN_CRYPTMGR_ENCRYPTKEY_FN GWEN_CryptMgr_SetEncryptKeyFn(GWEN_CRYPTMGR *cm,
|
|
GWEN_CRYPTMGR_ENCRYPTKEY_FN f) {
|
|||
GWEN_CRYPTMGR_ENCRYPTKEY_FN of;
|
|||
b2e1935d | martin | assert(cm);
|
|
eca2062e | martin | of=cm->encryptKeyFn;
|
|
b2e1935d | martin | cm->encryptKeyFn=f;
|
|
eca2062e | martin | return of;
|
|
b2e1935d | martin | }
|
|
eca2062e | martin | GWEN_CRYPTMGR_DECRYPTKEY_FN GWEN_CryptMgr_SetDecryptKeyFn(GWEN_CRYPTMGR *cm,
|
|
GWEN_CRYPTMGR_DECRYPTKEY_FN f) {
|
|||
GWEN_CRYPTMGR_DECRYPTKEY_FN of;
|
|||
b2e1935d | martin | assert(cm);
|
|
eca2062e | martin | of=cm->decryptKeyFn;
|
|
b2e1935d | martin | cm->decryptKeyFn=f;
|
|
eca2062e | martin | return of;
|
|
b2e1935d | martin | }
|
|
int GWEN_CryptMgr_Sign(GWEN_CRYPTMGR *cm, const uint8_t *pData, uint32_t lData, GWEN_BUFFER *dbuf) {
|
|||
GWEN_SIGHEAD *sh;
|
|||
GWEN_SIGTAIL *st;
|
|||
GWEN_TIME *ti;
|
|||
uint32_t pos;
|
|||
uint32_t shPos;
|
|||
uint8_t *p;
|
|||
uint32_t l;
|
|||
int rv;
|
|||
GWEN_BUFFER *sigbuf;
|
|||
assert(cm);
|
|||
GWEN_Buffer_AppendByte(dbuf, GWEN_CRYPTMGR_TLV_SIGNEDOBJECT);
|
|||
pos=GWEN_Buffer_GetPos(dbuf);
|
|||
GWEN_Buffer_AppendByte(dbuf, 0);
|
|||
GWEN_Buffer_AppendByte(dbuf, 0);
|
|||
/* prepare signature head */
|
|||
sh=GWEN_SigHead_new();
|
|||
GWEN_SigHead_SetKeyName(sh, cm->localKeyName);
|
|||
GWEN_SigHead_SetKeyNumber(sh, cm->localKeyNumber);
|
|||
GWEN_SigHead_SetKeyVersion(sh, cm->localKeyVersion);
|
|||
ti=GWEN_CurrentTime();
|
|||
GWEN_SigHead_SetDateTime(sh, ti);
|
|||
GWEN_Time_free(ti);
|
|||
GWEN_SigHead_SetSignatureProfile(sh, cm->signatureProfile);
|
|||
GWEN_SigHead_SetSignatureNumber(sh, 1);
|
|||
/* write signature head to buffer */
|
|||
shPos=GWEN_Buffer_GetPos(dbuf);
|
|||
rv=GWEN_SigHead_toBuffer(sh, dbuf, GWEN_CRYPTMGR_TLV_SIGHEAD);
|
|||
GWEN_SigHead_free(sh);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
return rv;
|
|||
}
|
|||
/* write data to buffer */
|
|||
if (pData && lData)
|
|||
GWEN_Tag16_DirectlyToBuffer(GWEN_CRYPTMGR_TLV_SIGDATA,
|
|||
(const char*)pData,
|
|||
lData,
|
|||
dbuf);
|
|||
/* sign data: signature head TLV + data TLV */
|
|||
sigbuf=GWEN_Buffer_new(0, 300, 0, 1);
|
|||
p=((uint8_t*)GWEN_Buffer_GetStart(dbuf))+shPos;
|
|||
l=GWEN_Buffer_GetPos(dbuf)-shPos;
|
|||
rv=GWEN_CryptMgr_SignData(cm, p, l, sigbuf);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
GWEN_Buffer_free(sigbuf);
|
|||
return rv;
|
|||
}
|
|||
/* create signature tail */
|
|||
st=GWEN_SigTail_new();
|
|||
GWEN_SigTail_SetSignature(st,
|
|||
(const uint8_t*)GWEN_Buffer_GetStart(sigbuf),
|
|||
GWEN_Buffer_GetUsedBytes(sigbuf));
|
|||
GWEN_Buffer_free(sigbuf);
|
|||
GWEN_SigTail_SetSignatureNumber(st, 1);
|
|||
/* write signature tail */
|
|||
rv=GWEN_SigTail_toBuffer(st, dbuf, GWEN_CRYPTMGR_TLV_SIGTAIL);
|
|||
GWEN_SigTail_free(st);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
return rv;
|
|||
}
|
|||
/* write complete size */
|
|||
l=GWEN_Buffer_GetPos(dbuf)-pos-2;
|
|||
p=(uint8_t*)GWEN_Buffer_GetStart(dbuf)+pos;
|
|||
*(p++)=l & 0xff;
|
|||
*p=(l>>8) & 0xff;
|
|||
return 0;
|
|||
}
|
|||
int GWEN_CryptMgr_Encrypt(GWEN_CRYPTMGR *cm, const uint8_t *pData, uint32_t lData, GWEN_BUFFER *dbuf) {
|
|||
GWEN_CRYPTHEAD *ch;
|
|||
uint32_t pos;
|
|||
uint8_t *p;
|
|||
uint32_t l;
|
|||
int rv;
|
|||
GWEN_BUFFER *cryptbuf;
|
|||
GWEN_BUFFER *tbuf;
|
|||
GWEN_CRYPT_KEY *mkey;
|
|||
assert(cm);
|
|||
/* generate a message key */
|
|||
mkey=GWEN_Crypt_KeyBlowFish_Generate(GWEN_Crypt_CryptMode_Cbc, 256/8, 2);
|
|||
if (mkey==NULL) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Unable to generate BLOWFISH key");
|
|||
return GWEN_ERROR_GENERIC;
|
|||
}
|
|||
GWEN_Buffer_AppendByte(dbuf, GWEN_CRYPTMGR_TLV_ENCRYPTEDOBJECT);
|
|||
pos=GWEN_Buffer_GetPos(dbuf);
|
|||
GWEN_Buffer_AppendByte(dbuf, 0);
|
|||
GWEN_Buffer_AppendByte(dbuf, 0);
|
|||
/* prepare signature head */
|
|||
ch=GWEN_CryptHead_new();
|
|||
GWEN_CryptHead_SetKeyName(ch, cm->peerKeyName);
|
|||
GWEN_CryptHead_SetKeyNumber(ch, cm->peerKeyNumber);
|
|||
GWEN_CryptHead_SetKeyVersion(ch, cm->peerKeyVersion);
|
|||
GWEN_CryptHead_SetCryptProfile(ch, cm->signatureProfile);
|
|||
/* encrypt key */
|
|||
cryptbuf=GWEN_Buffer_new(0, lData+256, 0, 1);
|
|||
rv=GWEN_CryptMgr_EncryptKey(cm,
|
|||
GWEN_Crypt_KeyBlowFish_GetKeyDataPtr(mkey),
|
|||
GWEN_Crypt_KeyBlowFish_GetKeyDataLen(mkey),
|
|||
cryptbuf);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
GWEN_Buffer_free(cryptbuf);
|
|||
GWEN_CryptHead_free(ch);
|
|||
GWEN_Crypt_Key_free(mkey);
|
|||
return rv;
|
|||
}
|
|||
GWEN_CryptHead_SetKey(ch,
|
|||
(const uint8_t*)GWEN_Buffer_GetStart(cryptbuf),
|
|||
GWEN_Buffer_GetUsedBytes(cryptbuf));
|
|||
GWEN_Buffer_free(cryptbuf);
|
|||
/* write crypt head to buffer */
|
|||
rv=GWEN_CryptHead_toBuffer(ch, dbuf, GWEN_CRYPTMGR_TLV_CRYPTHEAD);
|
|||
GWEN_CryptHead_free(ch);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
GWEN_Crypt_Key_free(mkey);
|
|||
return rv;
|
|||
}
|
|||
/* padd plain text data */
|
|||
tbuf=GWEN_Buffer_new(0, lData+256, 0, 1);
|
|||
GWEN_Buffer_AppendBytes(tbuf, (const char*)pData, lData);
|
|||
GWEN_Padd_PaddWithAnsiX9_23(tbuf);
|
|||
/* encrypt with message key */
|
|||
cryptbuf=GWEN_Buffer_new(0, lData+256, 0, 1);
|
|||
l=GWEN_Buffer_GetMaxUnsegmentedWrite(cryptbuf);
|
|||
rv=GWEN_Crypt_Key_Encipher(mkey,
|
|||
(const uint8_t*)GWEN_Buffer_GetStart(tbuf),
|
|||
GWEN_Buffer_GetUsedBytes(tbuf),
|
|||
(uint8_t*)GWEN_Buffer_GetStart(cryptbuf),
|
|||
&l);
|
|||
GWEN_Buffer_free(tbuf);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
GWEN_Buffer_free(cryptbuf);
|
|||
GWEN_Crypt_Key_free(mkey);
|
|||
return rv;
|
|||
}
|
|||
GWEN_Buffer_IncrementPos(cryptbuf, l);
|
|||
GWEN_Buffer_AdjustUsedBytes(cryptbuf);
|
|||
/* write encrypted data */
|
|||
GWEN_Tag16_DirectlyToBuffer(GWEN_CRYPTMGR_TLV_CRYPTDATA,
|
|||
GWEN_Buffer_GetStart(cryptbuf),
|
|||
GWEN_Buffer_GetUsedBytes(cryptbuf),
|
|||
dbuf);
|
|||
GWEN_Buffer_free(cryptbuf);
|
|||
GWEN_Crypt_Key_free(mkey);
|
|||
/* write complete size */
|
|||
l=GWEN_Buffer_GetPos(dbuf)-pos-2;
|
|||
p=(uint8_t*)GWEN_Buffer_GetStart(dbuf)+pos;
|
|||
*(p++)=l & 0xff;
|
|||
*p=(l>>8) & 0xff;
|
|||
return 0;
|
|||
}
|
|||
int GWEN_CryptMgr_Verify(GWEN_CRYPTMGR *cm, const uint8_t *pData, uint32_t lData, GWEN_BUFFER *dbuf) {
|
|||
GWEN_TAG16 *tag;
|
|||
const uint8_t *p;
|
|||
uint32_t l;
|
|||
GWEN_SIGHEAD *sh=NULL;
|
|||
GWEN_SIGTAIL *st=NULL;
|
|||
const uint8_t *pSignedData=NULL;
|
|||
uint32_t lSignedData=0;
|
|||
int rv;
|
|||
assert(cm);
|
|||
if (lData<3) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Too few bytes");
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
tag=GWEN_Tag16_fromBuffer2(pData, lData, 0);
|
|||
if (tag==NULL) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Data doesn't contain a valid TLV");
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
if (GWEN_Tag16_GetTagType(tag)!=GWEN_CRYPTMGR_TLV_SIGNEDOBJECT) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Data does not contain asigned object");
|
|||
GWEN_Tag16_free(tag);
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
p=GWEN_Tag16_GetTagData(tag);
|
|||
l=GWEN_Tag16_GetTagLength(tag);
|
|||
/* read sighead */
|
|||
if (l) {
|
|||
GWEN_TAG16 *subtag;
|
|||
subtag=GWEN_Tag16_fromBuffer2(p, l, 0);
|
|||
if (subtag) {
|
|||
if (GWEN_Tag16_GetTagType(subtag)==GWEN_CRYPTMGR_TLV_SIGHEAD) {
|
|||
sh=GWEN_SigHead_fromBuffer(GWEN_Tag16_GetTagData(subtag),
|
|||
GWEN_Tag16_GetTagLength(subtag));
|
|||
if (sh) {
|
|||
pSignedData=p;
|
|||
lSignedData=GWEN_Tag16_GetTagSize(subtag);
|
|||
}
|
|||
}
|
|||
p+=GWEN_Tag16_GetTagSize(subtag);
|
|||
l-=GWEN_Tag16_GetTagSize(subtag);
|
|||
GWEN_Tag16_free(subtag);
|
|||
}
|
|||
}
|
|||
/* read and store signed data */
|
|||
if (l) {
|
|||
GWEN_TAG16 *subtag;
|
|||
subtag=GWEN_Tag16_fromBuffer2(p, l, 0);
|
|||
if (subtag) {
|
|||
if (GWEN_Tag16_GetTagType(subtag)==GWEN_CRYPTMGR_TLV_SIGDATA) {
|
|||
GWEN_Buffer_AppendBytes(dbuf,
|
|||
GWEN_Tag16_GetTagData(subtag),
|
|||
GWEN_Tag16_GetTagLength(subtag));
|
|||
if ((pSignedData+lSignedData)==p) {
|
|||
lSignedData+=GWEN_Tag16_GetTagSize(subtag);
|
|||
}
|
|||
else {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "data TLV must follow sighead TLV");
|
|||
GWEN_Tag16_free(subtag);
|
|||
GWEN_SigHead_free(sh);
|
|||
GWEN_Tag16_free(tag);
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
}
|
|||
p+=GWEN_Tag16_GetTagSize(subtag);
|
|||
l-=GWEN_Tag16_GetTagSize(subtag);
|
|||
GWEN_Tag16_free(subtag);
|
|||
}
|
|||
}
|
|||
/* read sigtail (contains the signature) */
|
|||
if (l) {
|
|||
GWEN_TAG16 *subtag;
|
|||
subtag=GWEN_Tag16_fromBuffer2(p, l, 0);
|
|||
if (subtag) {
|
|||
if (GWEN_Tag16_GetTagType(subtag)==GWEN_CRYPTMGR_TLV_SIGTAIL) {
|
|||
st=GWEN_SigTail_fromBuffer(GWEN_Tag16_GetTagData(subtag),
|
|||
GWEN_Tag16_GetTagLength(subtag));
|
|||
}
|
|||
p+=GWEN_Tag16_GetTagSize(subtag);
|
|||
l-=GWEN_Tag16_GetTagSize(subtag);
|
|||
GWEN_Tag16_free(subtag);
|
|||
}
|
|||
}
|
|||
/* check for all needed components */
|
|||
if (!(sh && st && pSignedData && lSignedData)) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Signed object is not complete");
|
|||
GWEN_SigTail_free(st);
|
|||
GWEN_SigHead_free(sh);
|
|||
GWEN_Tag16_free(tag);
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
if (GWEN_SigHead_GetSignatureNumber(sh)!=GWEN_SigTail_GetSignatureNumber(st)) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Sighead doesn't match sigtail");
|
|||
GWEN_SigTail_free(st);
|
|||
GWEN_SigHead_free(sh);
|
|||
GWEN_Tag16_free(tag);
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
/* store or check peer key info */
|
|||
if (cm->peerKeyName==NULL) {
|
|||
/* store peer info */
|
|||
GWEN_CryptMgr_SetPeerKeyName(cm, GWEN_SigHead_GetKeyName(sh));
|
|||
GWEN_CryptMgr_SetPeerKeyNumber(cm, GWEN_SigHead_GetKeyNumber(sh));
|
|||
GWEN_CryptMgr_SetPeerKeyVersion(cm, GWEN_SigHead_GetKeyVersion(sh));
|
|||
}
|
|||
else {
|
|||
const char *s;
|
|||
/* compare peer info with expected info */
|
|||
s=GWEN_SigHead_GetKeyName(sh);
|
|||
if (!(cm->peerKeyName && s && (strcasecmp(cm->peerKeyName, s)==0) &&
|
|||
(cm->peerKeyNumber==GWEN_SigHead_GetKeyNumber(sh)) &&
|
|||
(cm->peerKeyVersion==GWEN_SigHead_GetKeyVersion(sh)))) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Unexpected peer key information in signature");
|
|||
GWEN_SigTail_free(st);
|
|||
GWEN_SigHead_free(sh);
|
|||
GWEN_Tag16_free(tag);
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
}
|
|||
/* verify signature */
|
|||
rv=GWEN_CryptMgr_VerifyData(cm,
|
|||
pSignedData, lSignedData,
|
|||
GWEN_SigTail_GetSignaturePtr(st),
|
|||
GWEN_SigTail_GetSignatureLen(st));
|
|||
GWEN_SigTail_free(st);
|
|||
GWEN_SigHead_free(sh);
|
|||
GWEN_Tag16_free(tag);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
return rv;
|
|||
}
|
|||
return 0;
|
|||
}
|
|||
int GWEN_CryptMgr_Decrypt(GWEN_CRYPTMGR *cm, const uint8_t *pData, uint32_t lData, GWEN_BUFFER *dbuf) {
|
|||
GWEN_TAG16 *tag;
|
|||
const uint8_t *p;
|
|||
uint32_t l;
|
|||
GWEN_CRYPTHEAD *ch=NULL;
|
|||
const uint8_t *pEncryptedData=NULL;
|
|||
uint32_t lEncryptedData=0;
|
|||
int rv;
|
|||
GWEN_BUFFER *tbuf;
|
|||
GWEN_CRYPT_KEY *mkey;
|
|||
assert(cm);
|
|||
if (lData<3) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Too few bytes");
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
tag=GWEN_Tag16_fromBuffer2(pData, lData, 0);
|
|||
if (tag==NULL) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Data doesn't contain a valid TLV");
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
if (GWEN_Tag16_GetTagType(tag)!=GWEN_CRYPTMGR_TLV_ENCRYPTEDOBJECT) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Data does not contain an encrypted object");
|
|||
GWEN_Tag16_free(tag);
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
p=GWEN_Tag16_GetTagData(tag);
|
|||
l=GWEN_Tag16_GetTagLength(tag);
|
|||
/* read crypthead */
|
|||
if (l) {
|
|||
GWEN_TAG16 *subtag;
|
|||
subtag=GWEN_Tag16_fromBuffer2(p, l, 0);
|
|||
if (subtag) {
|
|||
if (GWEN_Tag16_GetTagType(subtag)==GWEN_CRYPTMGR_TLV_CRYPTHEAD) {
|
|||
ch=GWEN_CryptHead_fromBuffer(GWEN_Tag16_GetTagData(subtag),
|
|||
GWEN_Tag16_GetTagLength(subtag));
|
|||
}
|
|||
p+=GWEN_Tag16_GetTagSize(subtag);
|
|||
l-=GWEN_Tag16_GetTagSize(subtag);
|
|||
GWEN_Tag16_free(subtag);
|
|||
}
|
|||
}
|
|||
/* read encrypted data */
|
|||
if (l) {
|
|||
GWEN_TAG16 *subtag;
|
|||
subtag=GWEN_Tag16_fromBuffer2(p, l, 0);
|
|||
if (subtag) {
|
|||
if (GWEN_Tag16_GetTagType(subtag)==GWEN_CRYPTMGR_TLV_CRYPTDATA) {
|
|||
pEncryptedData=GWEN_Tag16_GetTagData(subtag);
|
|||
lEncryptedData=GWEN_Tag16_GetTagLength(subtag);
|
|||
}
|
|||
p+=GWEN_Tag16_GetTagSize(subtag);
|
|||
l-=GWEN_Tag16_GetTagSize(subtag);
|
|||
GWEN_Tag16_free(subtag);
|
|||
}
|
|||
}
|
|||
/* check for all needed components */
|
|||
if (!(ch && pEncryptedData && lEncryptedData)) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Encrypted object is not complete");
|
|||
GWEN_CryptHead_free(ch);
|
|||
GWEN_Tag16_free(tag);
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
/* store or check peer key info */
|
|||
if (cm->localKeyName) {
|
|||
const char *s;
|
|||
/* compare peer info with expected info */
|
|||
s=GWEN_CryptHead_GetKeyName(ch);
|
|||
if (!(cm->localKeyName && s && (strcasecmp(cm->localKeyName, s)==0) &&
|
|||
(cm->localKeyNumber==GWEN_CryptHead_GetKeyNumber(ch)) &&
|
|||
(cm->localKeyVersion==GWEN_CryptHead_GetKeyVersion(ch)))) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Unexpected local key information in signature");
|
|||
GWEN_CryptHead_free(ch);
|
|||
GWEN_Tag16_free(tag);
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
}
|
|||
/* decrypt message key */
|
|||
tbuf=GWEN_Buffer_new(0, GWEN_CryptHead_GetKeyLen(ch), 0, 1);
|
|||
rv=GWEN_CryptMgr_DecryptKey(cm,
|
|||
GWEN_CryptHead_GetKeyPtr(ch),
|
|||
GWEN_CryptHead_GetKeyLen(ch),
|
|||
tbuf);
|
|||
GWEN_CryptHead_free(ch);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
GWEN_Buffer_free(tbuf);
|
|||
GWEN_Tag16_free(tag);
|
|||
return rv;
|
|||
}
|
|||
/* create message key */
|
|||
mkey=GWEN_Crypt_KeyBlowFish_fromData(GWEN_Crypt_CryptMode_Cbc,
|
|||
256/8,
|
|||
(const uint8_t*) GWEN_Buffer_GetStart(tbuf),
|
|||
GWEN_Buffer_GetUsedBytes(tbuf));
|
|||
GWEN_Buffer_free(tbuf);
|
|||
if (mkey==NULL) {
|
|||
DBG_ERROR(GWEN_LOGDOMAIN, "Unable to create BLOWFISH key from received data");
|
|||
GWEN_Tag16_free(tag);
|
|||
return GWEN_ERROR_BAD_DATA;
|
|||
}
|
|||
/* decrypt data with message key */
|
|||
tbuf=GWEN_Buffer_new(0, lEncryptedData+256, 0, 1);
|
|||
l=GWEN_Buffer_GetMaxUnsegmentedWrite(tbuf);
|
|||
rv=GWEN_Crypt_Key_Decipher(mkey,
|
|||
pEncryptedData, lEncryptedData,
|
|||
(uint8_t*)GWEN_Buffer_GetStart(tbuf),
|
|||
&l);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
GWEN_Buffer_free(tbuf);
|
|||
GWEN_Crypt_Key_free(mkey);
|
|||
GWEN_Tag16_free(tag);
|
|||
return rv;
|
|||
}
|
|||
GWEN_Buffer_IncrementPos(tbuf, l);
|
|||
GWEN_Buffer_AdjustUsedBytes(tbuf);
|
|||
/* unpadd data */
|
|||
rv=GWEN_Padd_UnpaddWithAnsiX9_23(tbuf);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
GWEN_Buffer_free(tbuf);
|
|||
GWEN_Crypt_Key_free(mkey);
|
|||
GWEN_Tag16_free(tag);
|
|||
return rv;
|
|||
}
|
|||
/* store data */
|
|||
GWEN_Buffer_AppendBuffer(dbuf, tbuf);
|
|||
GWEN_Buffer_free(tbuf);
|
|||
GWEN_Crypt_Key_free(mkey);
|
|||
GWEN_Tag16_free(tag);
|
|||
return 0;
|
|||
}
|
|||
int GWEN_CryptMgr_Encode(GWEN_CRYPTMGR *cm, const uint8_t *pData, uint32_t lData, GWEN_BUFFER *dbuf) {
|
|||
GWEN_BUFFER *tbuf;
|
|||
int rv;
|
|||
tbuf=GWEN_Buffer_new(0, lData, 0, 1);
|
|||
/* create signed object */
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "Signing data");
|
|||
rv=GWEN_CryptMgr_Sign(cm, pData, lData, tbuf);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
GWEN_Buffer_free(tbuf);
|
|||
return rv;
|
|||
}
|
|||
/* create encrypted object (containing a signed object in this case) */
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "Encrypting data");
|
|||
rv=GWEN_CryptMgr_Encrypt(cm,
|
|||
(const uint8_t*)GWEN_Buffer_GetStart(tbuf),
|
|||
GWEN_Buffer_GetUsedBytes(tbuf),
|
|||
dbuf);
|
|||
GWEN_Buffer_free(tbuf);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
return rv;
|
|||
}
|
|||
return 0;
|
|||
}
|
|||
int GWEN_CryptMgr_Decode(GWEN_CRYPTMGR *cm, const uint8_t *pData, uint32_t lData, GWEN_BUFFER *dbuf) {
|
|||
GWEN_BUFFER *tbuf;
|
|||
int rv;
|
|||
tbuf=GWEN_Buffer_new(0, lData, 0, 1);
|
|||
/* decrypt encrypted object */
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "Decrypting data");
|
|||
rv=GWEN_CryptMgr_Decrypt(cm, pData, lData, tbuf);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
GWEN_Buffer_free(tbuf);
|
|||
return rv;
|
|||
}
|
|||
/* verify signature, copy signed data to dbuf in the process */
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "Verifying data");
|
|||
rv=GWEN_CryptMgr_Verify(cm,
|
|||
(const uint8_t*)GWEN_Buffer_GetStart(tbuf),
|
|||
GWEN_Buffer_GetUsedBytes(tbuf),
|
|||
dbuf);
|
|||
GWEN_Buffer_free(tbuf);
|
|||
if (rv<0) {
|
|||
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|||
return rv;
|
|||
}
|
|||
return 0;
|
|||
}
|
|||