diff nss/lib/pkcs7/p7common.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/pkcs7/p7common.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,691 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * PKCS7 implementation -- the exported parts that are used whether
+ * creating or decoding.
+ */
+
+#include "p7local.h"
+
+#include "cert.h"
+#include "secitem.h"
+#include "secoid.h"
+#include "pk11func.h"
+
+/*
+ * Find out (saving pointer to lookup result for future reference)
+ * and return the inner content type.
+ */
+SECOidTag
+SEC_PKCS7ContentType (SEC_PKCS7ContentInfo *cinfo)
+{
+    if (cinfo->contentTypeTag == NULL)
+	cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
+
+    if (cinfo->contentTypeTag == NULL)
+	return SEC_OID_UNKNOWN;
+
+    return cinfo->contentTypeTag->offset;
+}
+
+
+/*
+ * Destroy a PKCS7 contentInfo and all of its sub-pieces.
+ */
+void
+SEC_PKCS7DestroyContentInfo(SEC_PKCS7ContentInfo *cinfo)
+{
+    SECOidTag kind;
+    CERTCertificate **certs;
+    CERTCertificateList **certlists;
+    SEC_PKCS7SignerInfo **signerinfos;
+    SEC_PKCS7RecipientInfo **recipientinfos;
+
+    PORT_Assert (cinfo->refCount > 0);
+    if (cinfo->refCount <= 0)
+	return;
+
+    cinfo->refCount--;
+    if (cinfo->refCount > 0)
+	return;
+
+    certs = NULL;
+    certlists = NULL;
+    recipientinfos = NULL;
+    signerinfos = NULL;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7EnvelopedData *edp;
+
+	    edp = cinfo->content.envelopedData;
+	    if (edp != NULL) {
+		recipientinfos = edp->recipientInfos;
+	    }
+	}
+	break;
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	{
+	    SEC_PKCS7SignedData *sdp;
+
+	    sdp = cinfo->content.signedData;
+	    if (sdp != NULL) {
+		certs = sdp->certs;
+		certlists = sdp->certLists;
+		signerinfos = sdp->signerInfos;
+	    }
+	}
+	break;
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saedp;
+
+	    saedp = cinfo->content.signedAndEnvelopedData;
+	    if (saedp != NULL) {
+		certs = saedp->certs;
+		certlists = saedp->certLists;
+		recipientinfos = saedp->recipientInfos;
+		signerinfos = saedp->signerInfos;
+		if (saedp->sigKey != NULL)
+		    PK11_FreeSymKey (saedp->sigKey);
+	    }
+	}
+	break;
+      default:
+	/* XXX Anything else that needs to be "manually" freed/destroyed? */
+	break;
+    }
+
+    if (certs != NULL) {
+	CERTCertificate *cert;
+
+	while ((cert = *certs++) != NULL) {
+	    CERT_DestroyCertificate (cert);
+	}
+    }
+
+    if (certlists != NULL) {
+	CERTCertificateList *certlist;
+
+	while ((certlist = *certlists++) != NULL) {
+	    CERT_DestroyCertificateList (certlist);
+	}
+    }
+
+    if (recipientinfos != NULL) {
+	SEC_PKCS7RecipientInfo *ri;
+
+	while ((ri = *recipientinfos++) != NULL) {
+	    if (ri->cert != NULL)
+		CERT_DestroyCertificate (ri->cert);
+	}
+    }
+
+    if (signerinfos != NULL) {
+	SEC_PKCS7SignerInfo *si;
+
+	while ((si = *signerinfos++) != NULL) {
+	    if (si->cert != NULL)
+		CERT_DestroyCertificate (si->cert);
+	    if (si->certList != NULL)
+		CERT_DestroyCertificateList (si->certList);
+	}
+    }
+
+    if (cinfo->poolp != NULL) {
+	PORT_FreeArena (cinfo->poolp, PR_FALSE);	/* XXX clear it? */
+    }
+}
+
+
+/*
+ * Return a copy of the given contentInfo.  The copy may be virtual
+ * or may be real -- either way, the result needs to be passed to
+ * SEC_PKCS7DestroyContentInfo later (as does the original).
+ */
+SEC_PKCS7ContentInfo *
+SEC_PKCS7CopyContentInfo(SEC_PKCS7ContentInfo *cinfo)
+{
+    if (cinfo == NULL)
+	return NULL;
+
+    PORT_Assert (cinfo->refCount > 0);
+
+    if (cinfo->created) {
+	/*
+	 * Want to do a real copy of these; otherwise subsequent
+	 * changes made to either copy are likely to be a surprise.
+	 * XXX I suspect that this will not actually be called for yet,
+	 * which is why the assert, so to notice if it is...
+	 */
+	PORT_Assert (0);
+	/*
+	 * XXX Create a new pool here, and copy everything from
+	 * within.  For cert stuff, need to call the appropriate
+	 * copy functions, etc.
+	 */
+    }
+
+    cinfo->refCount++;
+    return cinfo;
+}
+
+
+/*
+ * Return a pointer to the actual content.  In the case of those types
+ * which are encrypted, this returns the *plain* content.
+ * XXX Needs revisiting if/when we handle nested encrypted types.
+ */
+SECItem *
+SEC_PKCS7GetContent(SEC_PKCS7ContentInfo *cinfo)
+{
+    SECOidTag kind;
+
+    kind = SEC_PKCS7ContentType (cinfo);
+    switch (kind) {
+      case SEC_OID_PKCS7_DATA:
+	return cinfo->content.data;
+      case SEC_OID_PKCS7_DIGESTED_DATA:
+	{
+	    SEC_PKCS7DigestedData *digd;
+
+	    digd = cinfo->content.digestedData;
+	    if (digd == NULL)
+		break;
+	    return SEC_PKCS7GetContent (&(digd->contentInfo));
+	}
+      case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	{
+	    SEC_PKCS7EncryptedData *encd;
+
+	    encd = cinfo->content.encryptedData;
+	    if (encd == NULL)
+		break;
+	    return &(encd->encContentInfo.plainContent);
+	}
+      case SEC_OID_PKCS7_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7EnvelopedData *envd;
+
+	    envd = cinfo->content.envelopedData;
+	    if (envd == NULL)
+		break;
+	    return &(envd->encContentInfo.plainContent);
+	}
+      case SEC_OID_PKCS7_SIGNED_DATA:
+	{
+	    SEC_PKCS7SignedData *sigd;
+
+	    sigd = cinfo->content.signedData;
+	    if (sigd == NULL)
+		break;
+	    return SEC_PKCS7GetContent (&(sigd->contentInfo));
+	}
+      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+	{
+	    SEC_PKCS7SignedAndEnvelopedData *saed;
+
+	    saed = cinfo->content.signedAndEnvelopedData;
+	    if (saed == NULL)
+		break;
+	    return &(saed->encContentInfo.plainContent);
+	}
+      default:
+	PORT_Assert(0);
+	break;
+    }
+
+    return NULL;
+}
+
+
+/*
+ * XXX Fix the placement and formatting of the
+ * following routines (i.e. make them consistent with the rest of
+ * the pkcs7 code -- I think some/many belong in other files and
+ * they all need a formatting/style rehaul)
+ */
+
+/* retrieve the algorithm identifier for encrypted data.  
+ * the identifier returned is a copy of the algorithm identifier
+ * in the content info and needs to be freed after being used.
+ *
+ *   cinfo is the content info for which to retrieve the
+ *     encryption algorithm.
+ *
+ * if the content info is not encrypted data or an error 
+ * occurs NULL is returned.
+ */
+SECAlgorithmID *
+SEC_PKCS7GetEncryptionAlgorithm(SEC_PKCS7ContentInfo *cinfo)
+{
+  SECAlgorithmID *alg = 0;
+  switch (SEC_PKCS7ContentType(cinfo))
+    {
+    case SEC_OID_PKCS7_ENCRYPTED_DATA:
+      alg = &cinfo->content.encryptedData->encContentInfo.contentEncAlg;
+      break;
+    case SEC_OID_PKCS7_ENVELOPED_DATA:
+      alg = &cinfo->content.envelopedData->encContentInfo.contentEncAlg;
+      break;
+    case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
+      alg = &cinfo->content.signedAndEnvelopedData
+	->encContentInfo.contentEncAlg;
+      break;
+    default:
+      alg = 0;
+      break;
+    }
+
+    return alg;
+}
+
+/* set the content of the content info.  For data content infos,
+ * the data is set.  For encrytped content infos, the plainContent
+ * is set, and is expected to be encrypted later.
+ *  
+ * cinfo is the content info where the data will be set
+ *
+ * buf is a buffer of the data to set
+ *
+ * len is the length of the data being set.
+ *
+ * in the event of an error, SECFailure is returned.  SECSuccess 
+ * indicates the content was successfully set.
+ */
+SECStatus 
+SEC_PKCS7SetContent(SEC_PKCS7ContentInfo *cinfo,
+		    const char *buf, 
+		    unsigned long len)
+{
+    SECOidTag cinfo_type;
+    SECStatus rv;
+    SECItem content;
+    SECOidData *contentTypeTag = NULL;
+
+    content.type = siBuffer;
+    content.data = (unsigned char *)buf;
+    content.len = len;
+
+    cinfo_type = SEC_PKCS7ContentType(cinfo);
+
+    /* set inner content */
+    switch(cinfo_type)
+    {
+	case SEC_OID_PKCS7_SIGNED_DATA:
+	    if(content.len > 0) {
+		/* we "leak" the old content here, but as it's all in the pool */
+		/* it does not really matter */
+
+		/* create content item if necessary */
+		if (cinfo->content.signedData->contentInfo.content.data == NULL)
+		    cinfo->content.signedData->contentInfo.content.data = SECITEM_AllocItem(cinfo->poolp, NULL, 0);
+		rv = SECITEM_CopyItem(cinfo->poolp, 
+			cinfo->content.signedData->contentInfo.content.data,
+			&content);
+	    } else {
+		cinfo->content.signedData->contentInfo.content.data->data = NULL;
+		cinfo->content.signedData->contentInfo.content.data->len = 0;
+		rv = SECSuccess;
+	    }
+	    if(rv == SECFailure)
+		goto loser;
+	    
+	    break;
+	case SEC_OID_PKCS7_ENCRYPTED_DATA:
+	    /* XXX this forces the inner content type to be "data" */
+	    /* do we really want to override without asking or reason? */
+	    contentTypeTag = SECOID_FindOIDByTag(SEC_OID_PKCS7_DATA);
+	    if(contentTypeTag == NULL)
+		goto loser;
+	    rv = SECITEM_CopyItem(cinfo->poolp, 
+		&(cinfo->content.encryptedData->encContentInfo.contentType),
+		&(contentTypeTag->oid));
+	    if(rv == SECFailure)
+		goto loser;
+	    if(content.len > 0) {
+		rv = SECITEM_CopyItem(cinfo->poolp, 
+			&(cinfo->content.encryptedData->encContentInfo.plainContent),
+			&content);
+	    } else {
+		cinfo->content.encryptedData->encContentInfo.plainContent.data = NULL;
+		cinfo->content.encryptedData->encContentInfo.encContent.data = NULL;
+		cinfo->content.encryptedData->encContentInfo.plainContent.len = 0;
+		cinfo->content.encryptedData->encContentInfo.encContent.len = 0;
+		rv = SECSuccess;
+	    }
+	    if(rv == SECFailure)
+		goto loser;
+	    break;
+	case SEC_OID_PKCS7_DATA:
+	    cinfo->content.data = (SECItem *)PORT_ArenaZAlloc(cinfo->poolp,
+		sizeof(SECItem));
+	    if(cinfo->content.data == NULL)
+		goto loser;
+	    if(content.len > 0) {
+		rv = SECITEM_CopyItem(cinfo->poolp,
+			cinfo->content.data, &content);
+	    } else {
+	    	/* handle case with NULL content */
+		rv = SECSuccess;
+	    }
+	    if(rv == SECFailure)
+		goto loser;
+	    break;
+	default:
+	    goto loser;
+    }
+
+    return SECSuccess;
+
+loser:
+	
+    return SECFailure;
+}
+
+/* the content of an encrypted data content info is encrypted.
+ * it is assumed that for encrypted data, that the data has already
+ * been set and is in the "plainContent" field of the content info.
+ *
+ * cinfo is the content info to encrypt
+ *
+ * key is the key with which to perform the encryption.  if the
+ *     algorithm is a password based encryption algorithm, the
+ *     key is actually a password which will be processed per
+ *     PKCS #5.
+ * 
+ * in the event of an error, SECFailure is returned.  SECSuccess
+ * indicates a success.
+ */
+SECStatus 
+SEC_PKCS7EncryptContents(PLArenaPool *poolp,
+			 SEC_PKCS7ContentInfo *cinfo,
+			 SECItem *key,
+			 void *wincx)
+{
+    SECAlgorithmID *algid 	= NULL;
+    SECItem *       result 	= NULL;
+    SECItem *       src;
+    SECItem *       dest;
+    SECItem *       blocked_data = NULL;
+    void *          mark;
+    void *          cx;
+    PK11SymKey *    eKey 	= NULL;
+    PK11SlotInfo *  slot 	= NULL;
+
+    CK_MECHANISM_TYPE cryptoMechType;
+    int             bs;
+    SECStatus       rv 		= SECFailure;
+    SECItem         *c_param = NULL;
+
+    if((cinfo == NULL) || (key == NULL))
+	return SECFailure;
+
+    if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
+	return SECFailure;
+
+    algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);	
+    if(algid == NULL)
+	return SECFailure;
+
+    if(poolp == NULL)
+	poolp = cinfo->poolp;
+
+    mark = PORT_ArenaMark(poolp);
+    
+    src = &cinfo->content.encryptedData->encContentInfo.plainContent;
+    dest = &cinfo->content.encryptedData->encContentInfo.encContent;
+    dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
+    dest->len = (src->len + 64);
+    if(dest->data == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    slot = PK11_GetInternalKeySlot();
+    if(slot == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
+    if(eKey == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+    
+    cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
+    if (cryptoMechType == CKM_INVALID_MECHANISM) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    /* block according to PKCS 8 */
+    bs = PK11_GetBlockSize(cryptoMechType, c_param);
+    rv = SECSuccess;
+    if(bs) {
+	char pad_char;
+	pad_char = (char)(bs - (src->len % bs));
+	if(src->len % bs) {
+	    rv = SECSuccess;
+	    blocked_data = PK11_BlockData(src, bs);
+	    if(blocked_data) {
+		PORT_Memset((blocked_data->data + blocked_data->len 
+			    - (int)pad_char), 
+			    pad_char, (int)pad_char);
+	    } else {
+		rv = SECFailure;
+		goto loser;
+	    }
+	} else {
+	    blocked_data = SECITEM_DupItem(src);
+	    if(blocked_data) {
+		blocked_data->data = (unsigned char*)PORT_Realloc(
+						  blocked_data->data,
+						  blocked_data->len + bs);
+		if(blocked_data->data) {
+		    blocked_data->len += bs;
+		    PORT_Memset((blocked_data->data + src->len), (char)bs, bs);
+		} else {
+		    rv = SECFailure;
+		    goto loser;
+		}
+	    } else {
+		rv = SECFailure;
+		goto loser;
+	    }
+	 }
+    } else {
+	blocked_data = SECITEM_DupItem(src);
+	if(!blocked_data) {
+	    rv = SECFailure;
+	    goto loser;
+	}
+    }
+
+    cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT,
+		    		    eKey, c_param);
+    if(cx == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len), 
+		       (int)(src->len + 64), blocked_data->data, 
+		       (int)blocked_data->len);
+    PK11_DestroyContext((PK11Context*)cx, PR_TRUE);
+
+loser:
+    /* let success fall through */
+    if(blocked_data != NULL)
+	SECITEM_ZfreeItem(blocked_data, PR_TRUE);
+
+    if(result != NULL)
+	SECITEM_ZfreeItem(result, PR_TRUE);
+
+    if(rv == SECFailure)
+	PORT_ArenaRelease(poolp, mark);
+    else 
+	PORT_ArenaUnmark(poolp, mark);
+
+    if(eKey != NULL)
+	PK11_FreeSymKey(eKey);
+
+    if(slot != NULL)
+	PK11_FreeSlot(slot);
+
+    if(c_param != NULL) 
+	SECITEM_ZfreeItem(c_param, PR_TRUE);
+	
+    return rv;
+}
+
+/* the content of an encrypted data content info is decrypted.
+ * it is assumed that for encrypted data, that the data has already
+ * been set and is in the "encContent" field of the content info.
+ *
+ * cinfo is the content info to decrypt
+ *
+ * key is the key with which to perform the decryption.  if the
+ *     algorithm is a password based encryption algorithm, the
+ *     key is actually a password which will be processed per
+ *     PKCS #5.
+ * 
+ * in the event of an error, SECFailure is returned.  SECSuccess
+ * indicates a success.
+ */
+SECStatus 
+SEC_PKCS7DecryptContents(PLArenaPool *poolp,
+			 SEC_PKCS7ContentInfo *cinfo,
+			 SECItem *key,
+			 void *wincx)
+{
+    SECAlgorithmID *algid = NULL;
+    SECStatus rv = SECFailure;
+    SECItem *result = NULL, *dest, *src;
+    void *mark;
+
+    PK11SymKey *eKey = NULL;
+    PK11SlotInfo *slot = NULL;
+    CK_MECHANISM_TYPE cryptoMechType;
+    void *cx;
+    SECItem *c_param = NULL;
+    int bs;
+
+    if((cinfo == NULL) || (key == NULL))
+	return SECFailure;
+
+    if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
+	return SECFailure;
+
+    algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);	
+    if(algid == NULL)
+	return SECFailure;
+
+    if(poolp == NULL)
+	poolp = cinfo->poolp;
+
+    mark = PORT_ArenaMark(poolp);
+    
+    src = &cinfo->content.encryptedData->encContentInfo.encContent;
+    dest = &cinfo->content.encryptedData->encContentInfo.plainContent;
+    dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
+    dest->len = (src->len + 64);
+    if(dest->data == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    slot = PK11_GetInternalKeySlot();
+    if(slot == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
+    if(eKey == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+    
+    cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
+    if (cryptoMechType == CKM_INVALID_MECHANISM) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT,
+		    		    eKey, c_param);
+    if(cx == NULL) {
+	rv = SECFailure;
+	goto loser;
+    }
+
+    rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len), 
+		       (int)(src->len + 64), src->data, (int)src->len);
+    PK11_DestroyContext((PK11Context *)cx, PR_TRUE);
+
+    bs = PK11_GetBlockSize(cryptoMechType, c_param);
+    if(bs) {
+	/* check for proper badding in block algorithms.  this assumes
+	 * RC2 cbc or a DES cbc variant.  and the padding is thus defined
+	 */
+	if(((int)dest->data[dest->len-1] <= bs) && 
+	   ((int)dest->data[dest->len-1] > 0)) {
+	    dest->len -= (int)dest->data[dest->len-1];
+	} else {
+	    rv = SECFailure;
+	    /* set an error ? */
+	}
+    } 
+
+loser:
+    /* let success fall through */
+    if(result != NULL)
+	SECITEM_ZfreeItem(result, PR_TRUE);
+
+    if(rv == SECFailure)
+	PORT_ArenaRelease(poolp, mark);
+    else
+	PORT_ArenaUnmark(poolp, mark);
+
+    if(eKey != NULL)
+	PK11_FreeSymKey(eKey);
+
+    if(slot != NULL)
+	PK11_FreeSlot(slot);
+
+    if(c_param != NULL) 
+	SECITEM_ZfreeItem(c_param, PR_TRUE);
+	
+    return rv;
+}
+
+SECItem **
+SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo *cinfo)
+{
+    switch(SEC_PKCS7ContentType(cinfo))
+    {
+	case SEC_OID_PKCS7_SIGNED_DATA:
+	    return cinfo->content.signedData->rawCerts;
+	    break;
+	default:
+	    return NULL;
+	    break;
+    }
+}
+
+
+int
+SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo *cinfo)
+{
+  if (cinfo->contentTypeTag->offset == SEC_OID_PKCS7_ENVELOPED_DATA)
+    return cinfo->content.envelopedData->encContentInfo.keysize;
+  else
+    return 0;
+}
+
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)