Hi there, I need a little CMS wraper. I need decode S/MIME message chunk
by chunk. I start make it based on cmsutil. But I receive "segmentation
fault" every time on call NSS_CMSDecoder_Update. What's wrong?
//----- wraper code
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <string>
class SmimeDecoder //: public sigslot::has_slots<>
{
public:
SmimeDecoder();
SmimeDecoder(SmimeDecoder& sd);
~SmimeDecoder();
void PutCipherText(void* buffer, const int lenght);
/*sigslot::signal2<const void*, const int> OnHavePlainText;
sigslot::signal1<const int> OnDecryptionFailed;*/
char* PasswordCallback(PK11SlotInfo *slot, PRBool retry, void *arg);
void* _password_arg;
//static
PK11SymKey* KeyCallback(void *arg, SECAlgorithmID *algid);
void ContentCallback(void *arg, const char *buf, unsigned long len);
PK11SymKey* GetKey()
{
return _bulk_key;
}
void* getPassword()
{
return _password_arg;
}
void* getContentArg()
{
return NULL;
}
private:
PLArenaPool *_pool;
bool _begin_decoding;
void decode_message_start();
NSSCMSMessage * decode_message_append(void* buffer, const int lenght);
PK11SymKey *_bulk_key;
NSSCMSDecoderContext *_decoder_context;
NSSCMSMessage *_cms_message;
CERTCertDBHandle *_cert_db_handle;
};
SmimeDecoder::SmimeDecoder() : _begin_decoding(false), _pool(NULL)
{
//_key_callback = (NSSCMSGetDecryptKeyCallback)&this->KeyCallback;
//_key_callback = &SmimeDecoder::KeyCallback;
//_pool = PORT_NewArena(10240);
}
SmimeDecoder::SmimeDecoder(SmimeDecoder& sd)
{
}
SmimeDecoder::~SmimeDecoder()
{
}
PK11SymKey* key_callback_thunk(void* arg, SECAlgorithmID *algid)
{
SmimeDecoder* sd = reinterpret_cast<SmimeDecoder*>( arg );
return ( sd->KeyCallback(sd->GetKey(), algid) );
}
PK11SymKey* SmimeDecoder::KeyCallback(void *arg, SECAlgorithmID *algid)
{
return (PK11SymKey*)arg;
}
char* password_callback_thunk(PK11SlotInfo *slot, PRBool retry, void *arg)
{
SmimeDecoder* sd = reinterpret_cast<SmimeDecoder*>( arg );
return ( sd->PasswordCallback(slot, retry, sd->getPassword()) );
}
char* SmimeDecoder::PasswordCallback(PK11SlotInfo *slot, PRBool retry,
void *arg)
{
arg = NULL;
//PK11_SetPasswordFunc(SECU_GetModulePassword);
//PK11_SetPasswordFunc(&SECU_GetModulePassword);
//SECU_GetModulePassword();
}
void content_callback_thunk(void *arg, const char *buf, unsigned long len)
{
SmimeDecoder* sd = reinterpret_cast<SmimeDecoder*>( arg );
sd->ContentCallback(sd->getContentArg(), buf, len);
return;
}
void SmimeDecoder::ContentCallback(void *arg, const char *buf, unsigned
long len)
{
arg = NULL;
}
/*char * ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg)
{
char *passwd = NULL;
if ( (!retry) && arg ) {
passwd = PL_strdup((char *)arg);
}
return passwd;
}*/
void SmimeDecoder::PutCipherText(void* buffer, const int lenght)
{
NSSCMSMessage *msg = NULL;
if( !_begin_decoding ){//_begin_decoding == false
decode_message_start();//buffer, lenght);
msg = decode_message_append(buffer, lenght);
} else {//_begin_decoding == true
msg = decode_message_append(buffer, lenght);
//if ( isFinal ){
//}
}
}
void SmimeDecoder::decode_message_start()//void* buffer, const int lenght)
{
_begin_decoding = true;
PORT_SetError(0);
_decoder_context = NSS_CMSDecoder_Start(_pool,
//NULL, NULL,
content_callback_thunk, this,
// PasswordCallback,
_password_arg,
password_callback_thunk, this,
//KeyCallback,
key_callback_thunk,
this);//_bulk_key
if (!_decoder_context) {
std::cout << "shit happens!" << std::endl;
}
}
NSSCMSMessage * SmimeDecoder::decode_message_append(void* buffer, const
int lenght)
{
int nlevels;//, i;
SECItem sitem = { (SECItemType)0, 0, 0 };
//NSSCMSGetDecryptKeyCallback
//(void)
//_decoder_context
(void)NSS_CMSDecoder_Update(_decoder_context, (char *)buffer, lenght);
/*if (stat != SECSuccess) {
std::cout << "shit happens!" << std::endl;
}*/
/*if( !isFinal )
return _cms_message;
else
_cms_message = NSS_CMSDecoder_Finish( _decoder_context );
*/
nlevels = NSS_CMSMessage_ContentLevelCount(_cms_message);
for (int i = 0; i < nlevels; i++) {
NSSCMSContentInfo *cinfo;
SECOidTag typetag;
cinfo = NSS_CMSMessage_ContentLevel(_cms_message, i);
typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
/*if (decodeOptions->headerLevel >= 0)
fprintf(out, "\tlevel=%d.%d; ", decodeOptions->headerLevel, nlevels -
i);*/
switch (typetag) {
case SEC_OID_PKCS7_SIGNED_DATA:
{
NSSCMSSignedData *sigd = NULL;
SECItem **digests;
int nsigners;
int j;
/*if (decodeOptions->headerLevel >= 0)
fprintf(out, "type=signedData; ");*/
sigd = (NSSCMSSignedData
*)NSS_CMSContentInfo_GetContent(cinfo);
if (sigd == NULL) {
//SECU_PrintError(progName, "signedData component
missing");
goto loser;
}
/* if we have a content file, but no digests for this
signedData */
if (!NSS_CMSSignedData_HasDigests(sigd))
{//decodeOptions->content.data != NULL &&
PLArenaPool *poolp;
SECAlgorithmID **digestalgs;
/* detached content: grab content file */
//sitem = decodeOptions->content;
if ((poolp = PORT_NewArena(1024)) == NULL) {
fprintf(stderr, "cmsutil: Out of memory.\n");
goto loser;
}
digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd);
if (1)//DigestFile (poolp, &digests, &sitem,
digestalgs) != SECSuccess)
{
/* SECU_PrintError(progName,
"problem computing
message digest");*/
PORT_FreeArena(poolp, PR_FALSE);
goto loser;
}
if (NSS_CMSSignedData_SetDigests(sigd, digestalgs,
digests)
!= SECSuccess) {
/*SECU_PrintError(progName,
"problem setting
message digests");*/
PORT_FreeArena(poolp, PR_FALSE);
goto loser;
}
PORT_FreeArena(poolp, PR_FALSE);
}
/* import the certificates */
/*if (NSS_CMSSignedData_ImportCerts(sigd,
decodeOptions->options->certHandle,
decodeOptions->options->certUsage,
decodeOptions->keepCerts)
!= SECSuccess) {
SECU_PrintError(progName, "cert import failed");
goto loser;
}*/
/* find out about signers */
nsigners = NSS_CMSSignedData_SignerInfoCount(sigd);
/*if (decodeOptions->headerLevel >= 0)
fprintf(out, "nsigners=%d; ", nsigners);*/
if (nsigners == 0) {
/* Might be a cert transport message
** or might be an invalid message, such as a QA test
message
** or a message from an attacker.
*/
SECStatus rv;
/*rv = NSS_CMSSignedData_VerifyCertsOnly(sigd,
decodeOptions->options->certHandle,
decodeOptions->options->certUsage);*/
if (rv != SECSuccess) {
fprintf(stderr, "cmsutil: Verify certs-only
failed!\n");
goto loser;
}
return _cms_message;
}//cmsg
/* still no digests? */
if (!NSS_CMSSignedData_HasDigests(sigd)) {
//SECU_PrintError(progName, "no message digests");
goto loser;
}
for (j = 0; j < nsigners; j++) {
const char * svs;
NSSCMSSignerInfo *si;
NSSCMSVerificationStatus vs;
SECStatus bad;
si = NSS_CMSSignedData_GetSignerInfo(sigd, j);
if (1) {//decodeOptions->headerLevel >= 0
char *signercn;
static char empty[] = { "" };
signercn =
NSS_CMSSignerInfo_GetSignerCommonName(si);
if (signercn == NULL)
signercn = empty;
// fprintf(out, "\n\t\tsigner%d.id=\"%s\"; ", j,
signercn);
if (signercn != empty)
PORT_Free(signercn);
}
/*bad = NSS_CMSSignedData_VerifySignerInfo(sigd, j,
decodeOptions->options->certHandle,
decodeOptions->options->certUsage);*/
vs = NSS_CMSSignerInfo_GetVerificationStatus(si);
svs = NSS_CMSUtil_VerificationStatusToString(vs);
if (1){//decodeOptions->headerLevel >= 0) {
//fprintf(out, "signer%d.status=%s; ", j, svs);
/* goto loser ? */
} else if (1){//bad && out) {
fprintf(stderr, "signer %d status = %s\n", j,
svs);
goto loser;
}
}
}
break;
case SEC_OID_PKCS7_ENVELOPED_DATA:
//{
NSSCMSEnvelopedData *envd;
if (1)//decodeOptions->headerLevel >= 0)
//fprintf(out, "type=envelopedData; ");
envd = (NSSCMSEnvelopedData
*)NSS_CMSContentInfo_GetContent(cinfo);
if (envd == NULL) {
//SECU_PrintError(progName, "envelopedData component
missing");
goto loser;
}
//}
break;
case SEC_OID_PKCS7_ENCRYPTED_DATA:
//{
NSSCMSEncryptedData *encd;
if (1)//decodeOptions->headerLevel >= 0)
//fprintf(out, "type=encryptedData; ");
encd = (NSSCMSEncryptedData
*)NSS_CMSContentInfo_GetContent(cinfo);
if (encd == NULL) {
//SECU_PrintError(progName, "encryptedData component
missing");
goto loser;
}
//}
break;
case SEC_OID_PKCS7_DATA:
if (1)//decodeOptions->headerLevel >= 0)
//fprintf(out, "type=data; ");
break;
default:
break;
}//switch
//if (1)//decodeOptions->headerLevel >= 0)
//fprintf(out, "\n");
}
/*if (1){//!decodeOptions->suppressContent && out) {
SECItem *item = (sitem.data ? &sitem
:
NSS_CMSMessage_GetContent(cmsg));
if (item && item->data && item->len) {
fwrite(item->data, item->len, 1, out);
}
}*/
return _cms_message;
loser:
if (_cms_message)
NSS_CMSMessage_Destroy(_cms_message);
return NULL;
}
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::vector<char> base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::vector<char> ret;
while (in_len-- && ( encoded_string[in_] != '=') &&
is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] &
0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) +
((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret.push_back(char_array_3[i]);
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] &
0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) +
((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret.push_back(char_array_3[j]);
}
return ret;
}
int main(int argc, char **argv)
{
//Base64 encoded CMS message
std::string s =
std::string("MIAGCSqGSIb3DQEHAqCAMIACAQExADCABgkqhkiG9w0BBwGggCSAAAAAAAAA")
+std::string("oIIHCDCCAlIwggG7oAMCAQICASgwDQYJKoZIhvcNAQEEBQAwZDELMAkGA1UE")
+std::string("BhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWlu")
+std::string("IFZpZXcxEjAQBgNVBAoTCUJPR1VTIE5TUzEUMBIGA1UEAxMLTlNTIFRlc3Qg")
+std::string("Q0EwHhcNMDYxMTIxMTcxNTQzWhcNMTIwMjIxMTcxNTQzWjB6MQswCQYDVQQG")
+std::string("EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g")
+std::string("VmlldzESMBAGA1UEChMJQk9HVVMgTlNTMRwwGgYJKoZIhvcNAQkBFg1Cb2JA")
+std::string("Ym9ndXMuY29tMQwwCgYDVQQDEwNCb2IwgZ8wDQYJKoZIhvcNAQEBBQADgY0A")
+std::string("MIGJAoGBALYpHxqMyRkJ1Sl3ix3Drh5T/Vm1YQ/DgosHqL65hv64hVR94ISe")
+std::string("HvYxILTOKDljnNvlM/TdcFTUQYEz6n8BH4hGwvJ/lX7W7PWY8kYDz/ZalIQ1")
+std::string("laBLRT1KCb3brJaTBi5u5A3Em8SyrH4GVcGvwNnIrtLMfI3OjxCEdoG8lhq5")
+std::string("AgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAqwn3pLrQhweQwNOrrI9GUWM2B/bs")
+std::string("aAicmF9bqk3Rix2Xm8NJBWnJdjAaqNRB3TK4N2+65G0r3Bn7Thw5rjpoRW9z")
+std::string("bPZwJIVFaB5iwYr1io1drq116YLjg1Zx32tdJUAU96DiOMUfFU3BgZsTlWKM")
+std::string("w7Uka1i2bbG1DgAMLZzn0A4wggJUMIIBvaADAgECAgEyMA0GCSqGSIb3DQEB")
+std::string("BAUAMGQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYD")
+std::string("VQQHEw1Nb3VudGFpbiBWaWV3MRIwEAYDVQQKEwlCT0dVUyBOU1MxFDASBgNV")
+std::string("BAMTC05TUyBUZXN0IENBMB4XDTA2MTEyMTE3MTU0OFoXDTEyMDIyMTE3MTU0")
+std::string("OFowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNV")
+std::string("BAcTDU1vdW50YWluIFZpZXcxEjAQBgNVBAoTCUJPR1VTIE5TUzEdMBsGCSqG")
+std::string("SIb3DQEJARYORGF2ZUBib2d1cy5jb20xDTALBgNVBAMTBERhdmUwgZ8wDQYJ")
+std::string("KoZIhvcNAQEBBQADgY0AMIGJAoGBALrL1fn7MxUpq50Z70d3sEwGUeZK1I5H")
+std::string("2KEsGteIz+DsbqFgwY1xU9sskl91T83qHkvTE6DYUA+HGBvXDtzK0VxJYxZN")
+std::string("hSv550gr/G/F3HqI2Dr8KU3KH0k7Sqhw33hH3czznLXkZbFHv10XDVSAlrie")
+std::string("h2Ywe+K2m2nEDx+ChOgTAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAd8BEFq9F")
+std::string("EcYy3eFTwHpQYCZLoRT5/khLLgvX0GuK6fo28Mi3mFZqehW9Fazym2hF3H3m")
+std::string("O1he2U0j8L9j5yE66fEgPuq3dsO6IsmHGt98uucUAfiG+b/Wjw1YJQ+77ae+")
+std::string("+fwCOUHLKaPVSKJvqIP55LBaEMUwifaCmBq5lHtsWjkwggJWMIIBv6ADAgEC")
+std::string("AgEeMA0GCSqGSIb3DQEBBAUAMGQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpD")
+std::string("YWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRIwEAYDVQQKEwlC")
+std::string("T0dVUyBOU1MxFDASBgNVBAMTC05TUyBUZXN0IENBMB4XDTA2MTEyMTE3MTU0")
+std::string("MVoXDTEyMDIyMTE3MTU0MVowfjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNh")
+std::string("bGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxEjAQBgNVBAoTCUJP")
+std::string("R1VTIE5TUzEeMBwGCSqGSIb3DQEJARYPQWxpY2VAYm9ndXMuY29tMQ4wDAYD")
+std::string("VQQDEwVBbGljZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvR03fZov")
+std::string("RBwWvCvggwTF81wKcEeKYr24XBJbsJd5H1jOa+U8790gefGEJhk6iq0OIiUV")
+std::string("XIBjy1ywBlBAJ5BFtx6a1USjTVjIV79JJhCRAZ+9P+OH7EMrlZeVY8Zviu8L")
+std::string("7yRGEy37U6Fyeh+JxqCV8r43r0tR6801scS114rvuWUCAwEAATANBgkqhkiG")
+std::string("9w0BAQQFAAOBgQAlg7eydO8uGxgF0wVqYwv1bhUmD35+TuSQ9yNL9MP0i1VE")
+std::string("+QxnMHXWN6XL7IExOQl/uLN2AO/H6r8RDA7u4/DgyW8PHqL3ywZs3Hsfvamf")
+std::string("3TvO/TKzJlCr478p/4Jbi7lLNpKYMfmT5+JFx+KBFA7Qp6wcHTxFtgcsR8LQ")
+std::string("HIJlxDEAAAAAAAAA")
+std::string("====");
std::vector<char> str = base64_decode(s);
int len = str.size();
char *buffer = new char[len];
for (int i = 0; i < len; i++) {
*(buffer + i) = str[i];
}
smime::SmimeDecoder *dec = NULL;
dec = new smime::SmimeDecoder();
dec->PutCipherText(buffer, len);
delete dec;
delete buffer;
return 0;
}
_______________________________________________
dev-tech-crypto mailing list
dev-tech-crypto@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-tech-crypto