import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,48 @@
#! gmake
#
# 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/.
#######################################################################
# (1) Include initial platform-independent assignments (MANDATORY). #
#######################################################################
include manifest.mn
#######################################################################
# (2) Include "global" configuration information. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/config.mk
#######################################################################
# (3) Include "component" configuration information. (OPTIONAL) #
#######################################################################
#######################################################################
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
include config.mk
#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/rules.mk
#######################################################################
# (6) Execute "component" rules. (OPTIONAL) #
#######################################################################
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################

View file

@ -0,0 +1,528 @@
/* 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/. */
#include "cert.h"
#include "base64.h"
#include "secitem.h"
#include "secder.h"
#include "secasn1.h"
#include "secoid.h"
#include "secerr.h"
SEC_ASN1_MKSUB(SEC_AnyTemplate)
SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate)
typedef struct ContentInfoStr ContentInfo;
typedef struct DegenerateSignedDataStr DegenerateSignedData;
struct ContentInfoStr {
SECOidTag contentTypeTag; /* local; not part of encoding */
SECItem contentType;
union {
SECItem *data;
DegenerateSignedData *signedData;
} content;
};
struct DegenerateSignedDataStr {
SECItem version;
SECItem **digestAlgorithms;
ContentInfo contentInfo;
SECItem **certificates;
SECItem **crls;
SECItem **signerInfos;
};
static const SEC_ASN1Template *
choose_content_template(void *src_or_dest, PRBool encoding);
static const SEC_ASN1TemplateChooserPtr template_chooser = choose_content_template;
static const SEC_ASN1Template ContentInfoTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(ContentInfo) },
{ SEC_ASN1_OBJECT_ID,
offsetof(ContentInfo, contentType) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_DYNAMIC |
SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
offsetof(ContentInfo, content),
&template_chooser },
{ 0 }
};
static const SEC_ASN1Template DegenerateSignedDataTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(DegenerateSignedData) },
{ SEC_ASN1_INTEGER,
offsetof(DegenerateSignedData, version) },
{ SEC_ASN1_SET_OF | SEC_ASN1_XTRN,
offsetof(DegenerateSignedData, digestAlgorithms),
SEC_ASN1_SUB(SEC_AnyTemplate) },
{ SEC_ASN1_INLINE,
offsetof(DegenerateSignedData, contentInfo),
ContentInfoTemplate },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
SEC_ASN1_XTRN | 0,
offsetof(DegenerateSignedData, certificates),
SEC_ASN1_SUB(SEC_SetOfAnyTemplate) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
SEC_ASN1_XTRN | 1,
offsetof(DegenerateSignedData, crls),
SEC_ASN1_SUB(SEC_SetOfAnyTemplate) },
{ SEC_ASN1_SET_OF | SEC_ASN1_XTRN,
offsetof(DegenerateSignedData, signerInfos),
SEC_ASN1_SUB(SEC_AnyTemplate) },
{ 0 }
};
static const SEC_ASN1Template PointerToDegenerateSignedDataTemplate[] = {
{ SEC_ASN1_POINTER, 0, DegenerateSignedDataTemplate }
};
static SECOidTag
GetContentTypeTag(ContentInfo *cinfo)
{
if (cinfo->contentTypeTag == SEC_OID_UNKNOWN)
cinfo->contentTypeTag = SECOID_FindOIDTag(&cinfo->contentType);
return cinfo->contentTypeTag;
}
static const SEC_ASN1Template *
choose_content_template(void *src_or_dest, PRBool encoding)
{
const SEC_ASN1Template *theTemplate;
ContentInfo *cinfo;
SECOidTag kind;
PORT_Assert(src_or_dest != NULL);
if (src_or_dest == NULL)
return NULL;
cinfo = (ContentInfo *)src_or_dest;
kind = GetContentTypeTag(cinfo);
switch (kind) {
default:
theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate);
break;
case SEC_OID_PKCS7_DATA:
theTemplate = SEC_ASN1_GET(SEC_PointerToOctetStringTemplate);
break;
case SEC_OID_PKCS7_SIGNED_DATA:
theTemplate = PointerToDegenerateSignedDataTemplate;
break;
}
return theTemplate;
}
static SECStatus
SEC_ReadPKCS7Certs(SECItem *pkcs7Item, CERTImportCertificateFunc f, void *arg)
{
ContentInfo contentInfo;
SECStatus rv = SECFailure;
SECItem **certs;
int count;
PLArenaPool *arena;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
return rv;
}
PORT_Memset(&contentInfo, 0, sizeof(contentInfo));
if (SEC_ASN1DecodeItem(arena, &contentInfo, ContentInfoTemplate,
pkcs7Item) != SECSuccess) {
goto done;
}
if (GetContentTypeTag(&contentInfo) != SEC_OID_PKCS7_SIGNED_DATA) {
goto done;
}
rv = SECSuccess;
certs = contentInfo.content.signedData->certificates;
if (certs) {
count = 0;
while (*certs) {
count++;
certs++;
}
rv = (*f)(arg, contentInfo.content.signedData->certificates, count);
}
done:
if (arena) {
PORT_FreeArena(arena, PR_FALSE);
}
return rv;
}
const SEC_ASN1Template SEC_CertSequenceTemplate[] = {
{ SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
};
static SECStatus
SEC_ReadCertSequence(SECItem *certsItem, CERTImportCertificateFunc f, void *arg)
{
SECStatus rv = SECFailure;
SECItem **certs;
int count;
SECItem **rawCerts = NULL;
PLArenaPool *arena;
ContentInfo contentInfo;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
return rv;
}
PORT_Memset(&contentInfo, 0, sizeof(contentInfo));
if (SEC_ASN1DecodeItem(arena, &contentInfo, ContentInfoTemplate,
certsItem) != SECSuccess) {
goto done;
}
if (GetContentTypeTag(&contentInfo) != SEC_OID_NS_TYPE_CERT_SEQUENCE) {
goto done;
}
if (SEC_QuickDERDecodeItem(arena, &rawCerts, SEC_CertSequenceTemplate,
contentInfo.content.data) != SECSuccess) {
goto done;
}
rv = SECSuccess;
certs = rawCerts;
if (certs) {
count = 0;
while (*certs) {
count++;
certs++;
}
rv = (*f)(arg, rawCerts, count);
}
done:
if (arena) {
PORT_FreeArena(arena, PR_FALSE);
}
return rv;
}
CERTCertificate *
CERT_ConvertAndDecodeCertificate(char *certstr)
{
CERTCertificate *cert;
SECStatus rv;
SECItem der;
rv = ATOB_ConvertAsciiToItem(&der, certstr);
if (rv != SECSuccess)
return NULL;
cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
&der, NULL, PR_FALSE, PR_TRUE);
PORT_Free(der.data);
return cert;
}
static const char NS_CERT_HEADER[] = "-----BEGIN CERTIFICATE-----";
static const char NS_CERT_TRAILER[] = "-----END CERTIFICATE-----";
#define NS_CERT_HEADER_LEN ((sizeof NS_CERT_HEADER) - 1)
#define NS_CERT_TRAILER_LEN ((sizeof NS_CERT_TRAILER) - 1)
/*
* read an old style ascii or binary certificate chain
*/
SECStatus
CERT_DecodeCertPackage(char *certbuf,
int certlen,
CERTImportCertificateFunc f,
void *arg)
{
unsigned char *cp;
unsigned char *bincert = NULL;
char *ascCert = NULL;
SECStatus rv;
if (certbuf == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return (SECFailure);
}
/*
* Make sure certlen is long enough to handle the longest possible
* reference in the code below:
* 0x30 0x84 l1 l2 l3 l4 +
* tag 9 o1 o2 o3 o4 o5 o6 o7 o8 o9
* where 9 is the longest length of the expected oids we are testing.
* 6 + 11 = 17. 17 bytes is clearly too small to code any kind of
* certificate (a 128 bit ECC certificate contains at least an 8 byte
* key and a 16 byte signature, plus coding overhead). Typically a cert
* is much larger. So it's safe to require certlen to be at least 17
* bytes.
*/
if (certlen < 17) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return (SECFailure);
}
cp = (unsigned char *)certbuf;
/* is a DER encoded certificate of some type? */
if ((*cp & 0x1f) == SEC_ASN1_SEQUENCE) {
SECItem certitem;
SECItem *pcertitem = &certitem;
PRUint64 seqLen, seqLenLen;
cp++;
if (*cp & 0x80) {
/* Multibyte length */
seqLenLen = cp[0] & 0x7f;
switch (seqLenLen) {
case 4:
seqLen = ((unsigned long)cp[1] << 24) |
((unsigned long)cp[2] << 16) | (cp[3] << 8) | cp[4];
break;
case 3:
seqLen = ((unsigned long)cp[1] << 16) | (cp[2] << 8) | cp[3];
break;
case 2:
seqLen = (cp[1] << 8) | cp[2];
break;
case 1:
seqLen = cp[1];
break;
case 0:
/* indefinite length */
seqLen = 0;
break;
default:
goto notder;
}
cp += (seqLenLen + 1);
} else {
seqLenLen = 0;
seqLen = *cp;
cp++;
}
/* check entire length if definite length */
if (seqLen || seqLenLen) {
if (certlen != (seqLen + seqLenLen + 2L)) {
if (certlen > (seqLen + seqLenLen + 2L))
PORT_SetError(SEC_ERROR_EXTRA_INPUT);
else
PORT_SetError(SEC_ERROR_INPUT_LEN);
goto notder;
}
}
/* check the type oid */
if (cp[0] == SEC_ASN1_OBJECT_ID) {
SECOidData *oiddata;
SECItem oiditem;
/* XXX - assume DER encoding of OID len!! */
oiditem.len = cp[1];
/* if we add an oid below that is longer than 9 bytes, then we
* need to change the certlen check at the top of the function
* to prevent a buffer overflow
*/
if (oiditem.len > 9) {
PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
return (SECFailure);
}
oiditem.data = (unsigned char *)&cp[2];
oiddata = SECOID_FindOID(&oiditem);
if (oiddata == NULL) {
return (SECFailure);
}
certitem.data = (unsigned char *)certbuf;
certitem.len = certlen;
switch (oiddata->offset) {
case SEC_OID_PKCS7_SIGNED_DATA:
/* oid: 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02 */
return (SEC_ReadPKCS7Certs(&certitem, f, arg));
break;
case SEC_OID_NS_TYPE_CERT_SEQUENCE:
/* oid: 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x02, 0x05 */
return (SEC_ReadCertSequence(&certitem, f, arg));
break;
default:
break;
}
} else {
/* it had better be a certificate by now!! */
certitem.data = (unsigned char *)certbuf;
certitem.len = certlen;
rv = (*f)(arg, &pcertitem, 1);
return (rv);
}
}
/* now look for a netscape base64 ascii encoded cert */
notder : {
unsigned char *certbegin = NULL;
unsigned char *certend = NULL;
char *pc;
int cl;
/* Convert the ASCII data into a nul-terminated string */
ascCert = (char *)PORT_Alloc(certlen + 1);
if (!ascCert) {
rv = SECFailure;
goto loser;
}
PORT_Memcpy(ascCert, certbuf, certlen);
ascCert[certlen] = '\0';
pc = PORT_Strchr(ascCert, '\n'); /* find an EOL */
if (!pc) { /* maybe this is a MAC file */
pc = ascCert;
while (*pc && NULL != (pc = PORT_Strchr(pc, '\r'))) {
*pc++ = '\n';
}
}
cp = (unsigned char *)ascCert;
cl = certlen;
/* find the beginning marker */
while (cl > NS_CERT_HEADER_LEN) {
int found = 0;
if (!PORT_Strncasecmp((char *)cp, NS_CERT_HEADER,
NS_CERT_HEADER_LEN)) {
cl -= NS_CERT_HEADER_LEN;
cp += NS_CERT_HEADER_LEN;
found = 1;
}
/* skip to next eol */
while (cl && (*cp != '\n')) {
cp++;
cl--;
}
/* skip all blank lines */
while (cl && (*cp == '\n' || *cp == '\r')) {
cp++;
cl--;
}
if (cl && found) {
certbegin = cp;
break;
}
}
if (certbegin) {
/* find the ending marker */
while (cl >= NS_CERT_TRAILER_LEN) {
if (!PORT_Strncasecmp((char *)cp, NS_CERT_TRAILER,
NS_CERT_TRAILER_LEN)) {
certend = cp;
break;
}
/* skip to next eol */
while (cl && (*cp != '\n')) {
cp++;
cl--;
}
/* skip all blank lines */
while (cl && (*cp == '\n' || *cp == '\r')) {
cp++;
cl--;
}
}
}
if (certbegin && certend) {
unsigned int binLen;
*certend = 0;
/* convert to binary */
bincert = ATOB_AsciiToData((char *)certbegin, &binLen);
if (!bincert) {
rv = SECFailure;
goto loser;
}
/* now recurse to decode the binary */
rv = CERT_DecodeCertPackage((char *)bincert, binLen, f, arg);
} else {
PORT_SetError(SEC_ERROR_BAD_DER);
rv = SECFailure;
}
}
loser:
if (bincert) {
PORT_Free(bincert);
}
if (ascCert) {
PORT_Free(ascCert);
}
return (rv);
}
typedef struct {
PLArenaPool *arena;
SECItem cert;
} collect_args;
static SECStatus
collect_certs(void *arg, SECItem **certs, int numcerts)
{
SECStatus rv;
collect_args *collectArgs;
collectArgs = (collect_args *)arg;
rv = SECITEM_CopyItem(collectArgs->arena, &collectArgs->cert, *certs);
return (rv);
}
/*
* read an old style ascii or binary certificate
*/
CERTCertificate *
CERT_DecodeCertFromPackage(char *certbuf, int certlen)
{
collect_args collectArgs;
SECStatus rv;
CERTCertificate *cert = NULL;
collectArgs.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
rv = CERT_DecodeCertPackage(certbuf, certlen, collect_certs,
(void *)&collectArgs);
if (rv == SECSuccess) {
cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
&collectArgs.cert, NULL,
PR_FALSE, PR_TRUE);
}
PORT_FreeArena(collectArgs.arena, PR_FALSE);
return (cert);
}

View file

@ -0,0 +1,14 @@
#
# 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/.
#
# Override TARGETS variable so that only static libraries
# are specifed as dependencies within rules.mk.
#
TARGETS = $(LIBRARY)
SHARED_LIBRARY =
IMPORT_LIBRARY =
PROGRAM =

View file

@ -0,0 +1,33 @@
# 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/.
{
'includes': [
'../../coreconf/config.gypi'
],
'targets': [
{
'target_name': 'lib_pkcs7_exports',
'type': 'none',
'copies': [
{
'files': [
'pkcs7t.h',
'secmime.h',
'secpkcs7.h'
],
'destination': '<(nss_public_dist_dir)/<(module)'
},
{
'files': [
'p7local.h'
],
'destination': '<(nss_private_dist_dir)/<(module)'
}
]
}
],
'variables': {
'module': 'nss'
}
}

View file

@ -0,0 +1,33 @@
#
# 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/.
CORE_DEPTH = ../..
EXPORTS = \
secmime.h \
secpkcs7.h \
pkcs7t.h \
$(NULL)
PRIVATE_EXPORTS = \
p7local.h \
$(NULL)
MODULE = nss
CSRCS = \
certread.c \
p7common.c \
p7create.c \
p7decode.c \
p7encode.c \
p7local.c \
secmime.c \
$(NULL)
LIBRARY_NAME = pkcs7
# This part of the code, including all sub-dirs, can be optimized for size
export ALLOW_OPT_CODE_SIZE = 1

View file

@ -0,0 +1,663 @@
/* 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 *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 (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 *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 (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;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,137 @@
/* 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/. */
/*
* Support routines for PKCS7 implementation, none of which are exported.
* This file should only contain things that are needed by both the
* encoding/creation side *and* the decoding/decryption side. Anything
* else should just be static routines in the appropriate file.
*
* Do not export this file! If something in here is really needed outside
* of pkcs7 code, first try to add a PKCS7 interface which will do it for
* you. If that has a problem, then just move out what you need, changing
* its name as appropriate!
*/
#ifndef _P7LOCAL_H_
#define _P7LOCAL_H_
#include "secpkcs7.h"
#include "secasn1t.h"
extern const SEC_ASN1Template sec_PKCS7ContentInfoTemplate[];
/* opaque objects */
typedef struct sec_pkcs7_cipher_object sec_PKCS7CipherObject;
/************************************************************************/
SEC_BEGIN_PROTOS
/*
* Look through a set of attributes and find one that matches the
* specified object ID. If "only" is true, then make sure that
* there is not more than one attribute of the same type. Otherwise,
* just return the first one found. (XXX Does anybody really want
* that first-found behavior? It was like that when I found it...)
*/
extern SEC_PKCS7Attribute *sec_PKCS7FindAttribute(SEC_PKCS7Attribute **attrs,
SECOidTag oidtag,
PRBool only);
/*
* Return the single attribute value, doing some sanity checking first:
* - Multiple values are *not* expected.
* - Empty values are *not* expected.
*/
extern SECItem *sec_PKCS7AttributeValue(SEC_PKCS7Attribute *attr);
/*
* Encode a set of attributes (found in "src").
*/
extern SECItem *sec_PKCS7EncodeAttributes(PLArenaPool *poolp,
SECItem *dest, void *src);
/*
* Make sure that the order of the attributes guarantees valid DER
* (which must be in lexigraphically ascending order for a SET OF);
* if reordering is necessary it will be done in place (in attrs).
*/
extern SECStatus sec_PKCS7ReorderAttributes(SEC_PKCS7Attribute **attrs);
/*
* Create a context for decrypting, based on the given key and algorithm.
*/
extern sec_PKCS7CipherObject *
sec_PKCS7CreateDecryptObject(PK11SymKey *key, SECAlgorithmID *algid);
/*
* Create a context for encrypting, based on the given key and algorithm,
* and fill in the algorithm id.
*/
extern sec_PKCS7CipherObject *
sec_PKCS7CreateEncryptObject(PLArenaPool *poolp, PK11SymKey *key,
SECOidTag algtag, SECAlgorithmID *algid);
/*
* Destroy the given decryption or encryption object.
*/
extern void sec_PKCS7DestroyDecryptObject(sec_PKCS7CipherObject *obj);
extern void sec_PKCS7DestroyEncryptObject(sec_PKCS7CipherObject *obj);
/*
* What will be the output length of the next call to encrypt/decrypt?
* Result can be used to perform memory allocations. Note that the amount
* is exactly accurate only when not doing a block cipher or when final
* is false, otherwise it is an upper bound on the amount because until
* we see the data we do not know how many padding bytes there are
* (always between 1 and the cipher block size).
*
* Note that this can return zero, which does not mean that the cipher
* operation can be skipped! (It simply means that there are not enough
* bytes to make up an entire block; the bytes will be reserved until
* there are enough to encrypt/decrypt at least one block.) However,
* if zero is returned it *does* mean that no output buffer need be
* passed in to the subsequent cipher operation, as no output bytes
* will be stored.
*/
extern unsigned int sec_PKCS7DecryptLength(sec_PKCS7CipherObject *obj,
unsigned int input_len,
PRBool final);
extern unsigned int sec_PKCS7EncryptLength(sec_PKCS7CipherObject *obj,
unsigned int input_len,
PRBool final);
/*
* Decrypt a given length of input buffer (starting at "input" and
* containing "input_len" bytes), placing the decrypted bytes in
* "output" and storing the output length in "*output_len_p".
* "obj" is the return value from sec_PKCS7CreateDecryptObject.
* When "final" is true, this is the last of the data to be decrypted.
*/
extern SECStatus sec_PKCS7Decrypt(sec_PKCS7CipherObject *obj,
unsigned char *output,
unsigned int *output_len_p,
unsigned int max_output_len,
const unsigned char *input,
unsigned int input_len,
PRBool final);
/*
* Encrypt a given length of input buffer (starting at "input" and
* containing "input_len" bytes), placing the encrypted bytes in
* "output" and storing the output length in "*output_len_p".
* "obj" is the return value from sec_PKCS7CreateEncryptObject.
* When "final" is true, this is the last of the data to be encrypted.
*/
extern SECStatus sec_PKCS7Encrypt(sec_PKCS7CipherObject *obj,
unsigned char *output,
unsigned int *output_len_p,
unsigned int max_output_len,
const unsigned char *input,
unsigned int input_len,
PRBool final);
/************************************************************************/
SEC_END_PROTOS
#endif /* _P7LOCAL_H_ */

View file

@ -0,0 +1,29 @@
# 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/.
{
'includes': [
'../../coreconf/config.gypi'
],
'targets': [
{
'target_name': 'pkcs7',
'type': 'static_library',
'sources': [
'certread.c',
'p7common.c',
'p7create.c',
'p7decode.c',
'p7encode.c',
'p7local.c',
'secmime.c'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports'
]
}
],
'variables': {
'module': 'nss'
}
}

View file

@ -0,0 +1,233 @@
/* 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/. */
/*
* Header for pkcs7 types.
*/
#ifndef _PKCS7T_H_
#define _PKCS7T_H_
#include "plarena.h"
#include "seccomon.h"
#include "secoidt.h"
#include "certt.h"
#include "secmodt.h"
/* Opaque objects */
typedef struct SEC_PKCS7DecoderContextStr SEC_PKCS7DecoderContext;
typedef struct SEC_PKCS7EncoderContextStr SEC_PKCS7EncoderContext;
/* legacy defines that haven't been active for years */
typedef void *(*SECKEYGetPasswordKey)(void *arg, void *handle);
/* Non-opaque objects. NOTE, though: I want them to be treated as
* opaque as much as possible. If I could hide them completely,
* I would. (I tried, but ran into trouble that was taking me too
* much time to get out of.) I still intend to try to do so.
* In fact, the only type that "outsiders" should even *name* is
* SEC_PKCS7ContentInfo, and they should not reference its fields.
*/
/* rjr: PKCS #11 cert handling (pk11cert.c) does use SEC_PKCS7RecipientInfo's.
* This is because when we search the recipient list for the cert and key we
* want, we need to invert the order of the loops we used to have. The old
* loops were:
*
* For each recipient {
* find_cert = PK11_Find_AllCert(recipient->issuerSN);
* [which unrolls to... ]
* For each slot {
* Log into slot;
* search slot for cert;
* }
* }
*
* the new loop searchs all the recipients at once on a slot. this allows
* PKCS #11 to order slots in such a way that logout slots don't get checked
* if we can find the cert on a logged in slot. This eliminates lots of
* spurious password prompts when smart cards are installed... so why this
* comment? If you make SEC_PKCS7RecipientInfo completely opaque, you need
* to provide a non-opaque list of issuerSN's (the only field PKCS#11 needs
* and fix up pk11cert.c first. NOTE: Only S/MIME calls this special PKCS #11
* function.
*/
typedef struct SEC_PKCS7ContentInfoStr SEC_PKCS7ContentInfo;
typedef struct SEC_PKCS7SignedDataStr SEC_PKCS7SignedData;
typedef struct SEC_PKCS7EncryptedContentInfoStr SEC_PKCS7EncryptedContentInfo;
typedef struct SEC_PKCS7EnvelopedDataStr SEC_PKCS7EnvelopedData;
typedef struct SEC_PKCS7SignedAndEnvelopedDataStr
SEC_PKCS7SignedAndEnvelopedData;
typedef struct SEC_PKCS7SignerInfoStr SEC_PKCS7SignerInfo;
typedef struct SEC_PKCS7RecipientInfoStr SEC_PKCS7RecipientInfo;
typedef struct SEC_PKCS7DigestedDataStr SEC_PKCS7DigestedData;
typedef struct SEC_PKCS7EncryptedDataStr SEC_PKCS7EncryptedData;
/*
* The following is not actually a PKCS7 type, but for now it is only
* used by PKCS7, so we have adopted it. If someone else *ever* needs
* it, its name should be changed and it should be moved out of here.
* Do not dare to use it without doing so!
*/
typedef struct SEC_PKCS7AttributeStr SEC_PKCS7Attribute;
struct SEC_PKCS7ContentInfoStr {
PLArenaPool *poolp; /* local; not part of encoding */
PRBool created; /* local; not part of encoding */
int refCount; /* local; not part of encoding */
SECOidData *contentTypeTag; /* local; not part of encoding */
SECKEYGetPasswordKey pwfn; /* local; not part of encoding */
void *pwfn_arg; /* local; not part of encoding */
SECItem contentType;
union {
SECItem *data;
SEC_PKCS7DigestedData *digestedData;
SEC_PKCS7EncryptedData *encryptedData;
SEC_PKCS7EnvelopedData *envelopedData;
SEC_PKCS7SignedData *signedData;
SEC_PKCS7SignedAndEnvelopedData *signedAndEnvelopedData;
} content;
};
struct SEC_PKCS7SignedDataStr {
SECItem version;
SECAlgorithmID **digestAlgorithms;
SEC_PKCS7ContentInfo contentInfo;
SECItem **rawCerts;
CERTSignedCrl **crls;
SEC_PKCS7SignerInfo **signerInfos;
SECItem **digests; /* local; not part of encoding */
CERTCertificate **certs; /* local; not part of encoding */
CERTCertificateList **certLists; /* local; not part of encoding */
};
#define SEC_PKCS7_SIGNED_DATA_VERSION 1 /* what we *create* */
struct SEC_PKCS7EncryptedContentInfoStr {
SECOidData *contentTypeTag; /* local; not part of encoding */
SECItem contentType;
SECAlgorithmID contentEncAlg;
SECItem encContent;
SECItem plainContent; /* local; not part of encoding */
/* bytes not encrypted, but encoded */
int keysize; /* local; not part of encoding */
/* size of bulk encryption key
* (only used by creation code) */
SECOidTag encalg; /* local; not part of encoding */
/* oid tag of encryption algorithm
* (only used by creation code) */
};
struct SEC_PKCS7EnvelopedDataStr {
SECItem version;
SEC_PKCS7RecipientInfo **recipientInfos;
SEC_PKCS7EncryptedContentInfo encContentInfo;
};
#define SEC_PKCS7_ENVELOPED_DATA_VERSION 0 /* what we *create* */
struct SEC_PKCS7SignedAndEnvelopedDataStr {
SECItem version;
SEC_PKCS7RecipientInfo **recipientInfos;
SECAlgorithmID **digestAlgorithms;
SEC_PKCS7EncryptedContentInfo encContentInfo;
SECItem **rawCerts;
CERTSignedCrl **crls;
SEC_PKCS7SignerInfo **signerInfos;
SECItem **digests; /* local; not part of encoding */
CERTCertificate **certs; /* local; not part of encoding */
CERTCertificateList **certLists; /* local; not part of encoding */
PK11SymKey *sigKey; /* local; not part of encoding */
};
#define SEC_PKCS7_SIGNED_AND_ENVELOPED_DATA_VERSION 1 /* what we *create* */
struct SEC_PKCS7SignerInfoStr {
SECItem version;
CERTIssuerAndSN *issuerAndSN;
SECAlgorithmID digestAlg;
SEC_PKCS7Attribute **authAttr;
SECAlgorithmID digestEncAlg;
SECItem encDigest;
SEC_PKCS7Attribute **unAuthAttr;
CERTCertificate *cert; /* local; not part of encoding */
CERTCertificateList *certList; /* local; not part of encoding */
};
#define SEC_PKCS7_SIGNER_INFO_VERSION 1 /* what we *create* */
struct SEC_PKCS7RecipientInfoStr {
SECItem version;
CERTIssuerAndSN *issuerAndSN;
SECAlgorithmID keyEncAlg;
SECItem encKey;
CERTCertificate *cert; /* local; not part of encoding */
};
#define SEC_PKCS7_RECIPIENT_INFO_VERSION 0 /* what we *create* */
struct SEC_PKCS7DigestedDataStr {
SECItem version;
SECAlgorithmID digestAlg;
SEC_PKCS7ContentInfo contentInfo;
SECItem digest;
};
#define SEC_PKCS7_DIGESTED_DATA_VERSION 0 /* what we *create* */
struct SEC_PKCS7EncryptedDataStr {
SECItem version;
SEC_PKCS7EncryptedContentInfo encContentInfo;
};
#define SEC_PKCS7_ENCRYPTED_DATA_VERSION 0 /* what we *create* */
/*
* See comment above about this type not really belonging to PKCS7.
*/
struct SEC_PKCS7AttributeStr {
/* The following fields make up an encoded Attribute: */
SECItem type;
SECItem **values; /* data may or may not be encoded */
/* The following fields are not part of an encoded Attribute: */
SECOidData *typeTag;
PRBool encoded; /* when true, values are encoded */
};
/*
* Type of function passed to SEC_PKCS7Decode or SEC_PKCS7DecoderStart.
* If specified, this is where the content bytes (only) will be "sent"
* as they are recovered during the decoding.
*
* XXX Should just combine this with SEC_PKCS7EncoderContentCallback type
* and use a simpler, common name.
*/
typedef void (*SEC_PKCS7DecoderContentCallback)(void *arg,
const char *buf,
unsigned long len);
/*
* Type of function passed to SEC_PKCS7Encode or SEC_PKCS7EncoderStart.
* This is where the encoded bytes will be "sent".
*
* XXX Should just combine this with SEC_PKCS7DecoderContentCallback type
* and use a simpler, common name.
*/
typedef void (*SEC_PKCS7EncoderOutputCallback)(void *arg,
const char *buf,
unsigned long len);
/*
* Type of function passed to SEC_PKCS7Decode or SEC_PKCS7DecoderStart
* to retrieve the decryption key. This function is inteded to be
* used for EncryptedData content info's which do not have a key available
* in a certificate, etc.
*/
typedef PK11SymKey *(*SEC_PKCS7GetDecryptKeyCallback)(void *arg,
SECAlgorithmID *algid);
/*
* Type of function passed to SEC_PKCS7Decode or SEC_PKCS7DecoderStart.
* This function in intended to be used to verify that decrypting a
* particular crypto algorithm is allowed. Content types which do not
* require decryption will not need the callback. If the callback
* is not specified for content types which require decryption, the
* decryption will be disallowed.
*/
typedef PRBool (*SEC_PKCS7DecryptionAllowedCallback)(SECAlgorithmID *algid,
PK11SymKey *bulkkey);
#endif /* _PKCS7T_H_ */

View file

@ -0,0 +1,800 @@
/* 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/. */
/*
* Stuff specific to S/MIME policy and interoperability.
* Depends on PKCS7, but there should be no dependency the other way around.
*/
#include "secmime.h"
#include "secoid.h"
#include "pk11func.h"
#include "ciferfam.h" /* for CIPHER_FAMILY symbols */
#include "secasn1.h"
#include "secitem.h"
#include "cert.h"
#include "key.h"
#include "secerr.h"
typedef struct smime_cipher_map_struct {
unsigned long cipher;
SECOidTag algtag;
SECItem *parms;
} smime_cipher_map;
/*
* These are macros because I think some subsequent parameters,
* like those for RC5, will want to use them, too, separately.
*/
#define SMIME_DER_INTVAL_16 SEC_ASN1_INTEGER, 0x01, 0x10
#define SMIME_DER_INTVAL_40 SEC_ASN1_INTEGER, 0x01, 0x28
#define SMIME_DER_INTVAL_64 SEC_ASN1_INTEGER, 0x01, 0x40
#define SMIME_DER_INTVAL_128 SEC_ASN1_INTEGER, 0x02, 0x00, 0x80
#ifdef SMIME_DOES_RC5 /* will be needed; quiet unused warning for now */
static unsigned char smime_int16[] = { SMIME_DER_INTVAL_16 };
#endif
static unsigned char smime_int40[] = { SMIME_DER_INTVAL_40 };
static unsigned char smime_int64[] = { SMIME_DER_INTVAL_64 };
static unsigned char smime_int128[] = { SMIME_DER_INTVAL_128 };
static SECItem smime_rc2p40 = { siBuffer, smime_int40, sizeof(smime_int40) };
static SECItem smime_rc2p64 = { siBuffer, smime_int64, sizeof(smime_int64) };
static SECItem smime_rc2p128 = { siBuffer, smime_int128, sizeof(smime_int128) };
static smime_cipher_map smime_cipher_maps[] = {
{ SMIME_RC2_CBC_40, SEC_OID_RC2_CBC, &smime_rc2p40 },
{ SMIME_RC2_CBC_64, SEC_OID_RC2_CBC, &smime_rc2p64 },
{ SMIME_RC2_CBC_128, SEC_OID_RC2_CBC, &smime_rc2p128 },
#ifdef SMIME_DOES_RC5
{ SMIME_RC5PAD_64_16_40, SEC_OID_RC5_CBC_PAD, &smime_rc5p40 },
{ SMIME_RC5PAD_64_16_64, SEC_OID_RC5_CBC_PAD, &smime_rc5p64 },
{ SMIME_RC5PAD_64_16_128, SEC_OID_RC5_CBC_PAD, &smime_rc5p128 },
#endif
{ SMIME_DES_CBC_56, SEC_OID_DES_CBC, NULL },
{ SMIME_DES_EDE3_168, SEC_OID_DES_EDE3_CBC, NULL }
};
/*
* Note, the following value really just needs to be an upper bound
* on the ciphers.
*/
static const int smime_symmetric_count = sizeof(smime_cipher_maps) / sizeof(smime_cipher_map);
static unsigned long *smime_prefs, *smime_newprefs;
static int smime_current_pref_index = 0;
static PRBool smime_prefs_complete = PR_FALSE;
static PRBool smime_prefs_changed = PR_TRUE;
static unsigned long smime_policy_bits = 0;
static int
smime_mapi_by_cipher(unsigned long cipher)
{
int i;
for (i = 0; i < smime_symmetric_count; i++) {
if (smime_cipher_maps[i].cipher == cipher)
break;
}
if (i == smime_symmetric_count)
return -1;
return i;
}
/*
* this function locally records the user's preference
*/
SECStatus
SECMIME_EnableCipher(long which, int on)
{
unsigned long mask;
if (smime_newprefs == NULL || smime_prefs_complete) {
/*
* This is either the very first time, or we are starting over.
*/
smime_newprefs = (unsigned long *)PORT_ZAlloc(smime_symmetric_count * sizeof(*smime_newprefs));
if (smime_newprefs == NULL)
return SECFailure;
smime_current_pref_index = 0;
smime_prefs_complete = PR_FALSE;
}
mask = which & CIPHER_FAMILYID_MASK;
if (mask == CIPHER_FAMILYID_MASK) {
/*
* This call signifies that all preferences have been set.
* Move "newprefs" over, after checking first whether or
* not the new ones are different from the old ones.
*/
if (smime_prefs != NULL) {
if (PORT_Memcmp(smime_prefs, smime_newprefs,
smime_symmetric_count * sizeof(*smime_prefs)) == 0)
smime_prefs_changed = PR_FALSE;
else
smime_prefs_changed = PR_TRUE;
PORT_Free(smime_prefs);
}
smime_prefs = smime_newprefs;
smime_prefs_complete = PR_TRUE;
return SECSuccess;
}
PORT_Assert(mask == CIPHER_FAMILYID_SMIME);
if (mask != CIPHER_FAMILYID_SMIME) {
/* XXX set an error! */
return SECFailure;
}
if (on) {
PORT_Assert(smime_current_pref_index < smime_symmetric_count);
if (smime_current_pref_index >= smime_symmetric_count) {
/* XXX set an error! */
return SECFailure;
}
smime_newprefs[smime_current_pref_index++] = which;
}
return SECSuccess;
}
/*
* this function locally records the export policy
*/
SECStatus
SECMIME_SetPolicy(long which, int on)
{
unsigned long mask;
PORT_Assert((which & CIPHER_FAMILYID_MASK) == CIPHER_FAMILYID_SMIME);
if ((which & CIPHER_FAMILYID_MASK) != CIPHER_FAMILYID_SMIME) {
/* XXX set an error! */
return SECFailure;
}
which &= ~CIPHER_FAMILYID_MASK;
PORT_Assert(which < 32); /* bits in the long */
if (which >= 32) {
/* XXX set an error! */
return SECFailure;
}
mask = 1UL << which;
if (on) {
smime_policy_bits |= mask;
} else {
smime_policy_bits &= ~mask;
}
return SECSuccess;
}
/*
* Based on the given algorithm (including its parameters, in some cases!)
* and the given key (may or may not be inspected, depending on the
* algorithm), find the appropriate policy algorithm specification
* and return it. If no match can be made, -1 is returned.
*/
static long
smime_policy_algorithm(SECAlgorithmID *algid, PK11SymKey *key)
{
SECOidTag algtag;
algtag = SECOID_GetAlgorithmTag(algid);
switch (algtag) {
case SEC_OID_RC2_CBC: {
unsigned int keylen_bits;
keylen_bits = PK11_GetKeyStrength(key, algid);
switch (keylen_bits) {
case 40:
return SMIME_RC2_CBC_40;
case 64:
return SMIME_RC2_CBC_64;
case 128:
return SMIME_RC2_CBC_128;
default:
break;
}
} break;
case SEC_OID_DES_CBC:
return SMIME_DES_CBC_56;
case SEC_OID_DES_EDE3_CBC:
return SMIME_DES_EDE3_168;
#ifdef SMIME_DOES_RC5
case SEC_OID_RC5_CBC_PAD:
PORT_Assert(0); /* XXX need to pull out parameters and match */
break;
#endif
default:
break;
}
return -1;
}
static PRBool
smime_cipher_allowed(unsigned long which)
{
unsigned long mask;
which &= ~CIPHER_FAMILYID_MASK;
PORT_Assert(which < 32); /* bits per long (min) */
if (which >= 32)
return PR_FALSE;
mask = 1UL << which;
if ((mask & smime_policy_bits) == 0)
return PR_FALSE;
return PR_TRUE;
}
PRBool
SECMIME_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key)
{
long which;
which = smime_policy_algorithm(algid, key);
if (which < 0)
return PR_FALSE;
return smime_cipher_allowed((unsigned long)which);
}
/*
* Does the current policy allow *any* S/MIME encryption (or decryption)?
*
* This tells whether or not *any* S/MIME encryption can be done,
* according to policy. Callers may use this to do nicer user interface
* (say, greying out a checkbox so a user does not even try to encrypt
* a message when they are not allowed to) or for any reason they want
* to check whether S/MIME encryption (or decryption, for that matter)
* may be done.
*
* It takes no arguments. The return value is a simple boolean:
* PR_TRUE means encryption (or decryption) is *possible*
* (but may still fail due to other reasons, like because we cannot
* find all the necessary certs, etc.; PR_TRUE is *not* a guarantee)
* PR_FALSE means encryption (or decryption) is not permitted
*
* There are no errors from this routine.
*/
PRBool
SECMIME_EncryptionPossible(void)
{
if (smime_policy_bits != 0)
return PR_TRUE;
return PR_FALSE;
}
/*
* XXX Would like the "parameters" field to be a SECItem *, but the
* encoder is having trouble with optional pointers to an ANY. Maybe
* once that is fixed, can change this back...
*/
typedef struct smime_capability_struct {
unsigned long cipher; /* local; not part of encoding */
SECOidTag capIDTag; /* local; not part of encoding */
SECItem capabilityID;
SECItem parameters;
} smime_capability;
static const SEC_ASN1Template smime_capability_template[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(smime_capability) },
{ SEC_ASN1_OBJECT_ID,
offsetof(smime_capability, capabilityID) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
offsetof(smime_capability, parameters) },
{ 0 }
};
static const SEC_ASN1Template smime_capabilities_template[] = {
{ SEC_ASN1_SEQUENCE_OF, 0, smime_capability_template }
};
static void
smime_fill_capability(smime_capability *cap)
{
unsigned long cipher;
SECOidTag algtag;
int i;
algtag = SECOID_FindOIDTag(&(cap->capabilityID));
for (i = 0; i < smime_symmetric_count; i++) {
if (smime_cipher_maps[i].algtag != algtag)
continue;
/*
* XXX If SECITEM_CompareItem allowed NULLs as arguments (comparing
* 2 NULLs as equal and NULL and non-NULL as not equal), we could
* use that here instead of all of the following comparison code.
*/
if (cap->parameters.data != NULL) {
if (smime_cipher_maps[i].parms == NULL)
continue;
if (cap->parameters.len != smime_cipher_maps[i].parms->len)
continue;
if (PORT_Memcmp(cap->parameters.data,
smime_cipher_maps[i].parms->data,
cap->parameters.len) == 0)
break;
} else if (smime_cipher_maps[i].parms == NULL) {
break;
}
}
if (i == smime_symmetric_count)
cipher = 0;
else
cipher = smime_cipher_maps[i].cipher;
cap->cipher = cipher;
cap->capIDTag = algtag;
}
static long
smime_choose_cipher(CERTCertificate *scert, CERTCertificate **rcerts)
{
PLArenaPool *poolp;
long chosen_cipher;
int *cipher_abilities;
int *cipher_votes;
int strong_mapi;
int rcount, mapi, max;
if (smime_policy_bits == 0) {
PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM);
return -1;
}
chosen_cipher = SMIME_RC2_CBC_40; /* the default, LCD */
poolp = PORT_NewArena(1024); /* XXX what is right value? */
if (poolp == NULL)
goto done;
cipher_abilities = (int *)PORT_ArenaZAlloc(poolp,
smime_symmetric_count * sizeof(int));
if (cipher_abilities == NULL)
goto done;
cipher_votes = (int *)PORT_ArenaZAlloc(poolp,
smime_symmetric_count * sizeof(int));
if (cipher_votes == NULL)
goto done;
/*
* XXX Should have a #define somewhere which specifies default
* strong cipher. (Or better, a way to configure.)
*/
/* Make triple-DES the strong cipher. */
strong_mapi = smime_mapi_by_cipher(SMIME_DES_EDE3_168);
PORT_Assert(strong_mapi >= 0);
for (rcount = 0; rcerts[rcount] != NULL; rcount++) {
SECItem *profile;
smime_capability **caps;
int capi, pref;
SECStatus dstat;
pref = smime_symmetric_count;
profile = CERT_FindSMimeProfile(rcerts[rcount]);
if (profile != NULL && profile->data != NULL && profile->len > 0) {
caps = NULL;
dstat = SEC_QuickDERDecodeItem(poolp, &caps,
smime_capabilities_template,
profile);
if (dstat == SECSuccess && caps != NULL) {
for (capi = 0; caps[capi] != NULL; capi++) {
smime_fill_capability(caps[capi]);
mapi = smime_mapi_by_cipher(caps[capi]->cipher);
if (mapi >= 0) {
cipher_abilities[mapi]++;
cipher_votes[mapi] += pref;
--pref;
}
}
}
} else {
SECKEYPublicKey *key;
unsigned int pklen_bits;
/*
* XXX This is probably only good for RSA keys. What I would
* really like is a function to just say; Is the public key in
* this cert an export-length key? Then I would not have to
* know things like the value 512, or the kind of key, or what
* a subjectPublicKeyInfo is, etc.
*/
key = CERT_ExtractPublicKey(rcerts[rcount]);
if (key != NULL) {
pklen_bits = SECKEY_PublicKeyStrength(key) * 8;
SECKEY_DestroyPublicKey(key);
if (pklen_bits > 512) {
cipher_abilities[strong_mapi]++;
cipher_votes[strong_mapi] += pref;
}
}
}
if (profile != NULL)
SECITEM_FreeItem(profile, PR_TRUE);
}
max = 0;
for (mapi = 0; mapi < smime_symmetric_count; mapi++) {
if (cipher_abilities[mapi] != rcount)
continue;
if (!smime_cipher_allowed(smime_cipher_maps[mapi].cipher))
continue;
if (cipher_votes[mapi] > max) {
chosen_cipher = smime_cipher_maps[mapi].cipher;
max = cipher_votes[mapi];
} /* XXX else if a tie, let scert break it? */
}
done:
if (poolp != NULL)
PORT_FreeArena(poolp, PR_FALSE);
return chosen_cipher;
}
/*
* XXX This is a hack for now to satisfy our current interface.
* Eventually, with more parameters needing to be specified, just
* looking up the keysize is not going to be sufficient.
*/
static int
smime_keysize_by_cipher(unsigned long which)
{
int keysize;
switch (which) {
case SMIME_RC2_CBC_40:
keysize = 40;
break;
case SMIME_RC2_CBC_64:
keysize = 64;
break;
case SMIME_RC2_CBC_128:
keysize = 128;
break;
#ifdef SMIME_DOES_RC5
case SMIME_RC5PAD_64_16_40:
case SMIME_RC5PAD_64_16_64:
case SMIME_RC5PAD_64_16_128:
/* XXX See comment above; keysize is not enough... */
PORT_Assert(0);
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
keysize = -1;
break;
#endif
case SMIME_DES_CBC_56:
case SMIME_DES_EDE3_168:
/*
* These are special; since the key size is fixed, we actually
* want to *avoid* specifying a key size.
*/
keysize = 0;
break;
default:
keysize = -1;
break;
}
return keysize;
}
/*
* Start an S/MIME encrypting context.
*
* "scert" is the cert for the sender. It will be checked for validity.
* "rcerts" are the certs for the recipients. They will also be checked.
*
* "certdb" is the cert database to use for verifying the certs.
* It can be NULL if a default database is available (like in the client).
*
* This function already does all of the stuff specific to S/MIME protocol
* and local policy; the return value just needs to be passed to
* SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
* and finally to SEC_PKCS7DestroyContentInfo().
*
* An error results in a return value of NULL and an error set.
* (Retrieve specific errors via PORT_GetError()/XP_GetError().)
*/
SEC_PKCS7ContentInfo *
SECMIME_CreateEncrypted(CERTCertificate *scert,
CERTCertificate **rcerts,
CERTCertDBHandle *certdb,
SECKEYGetPasswordKey pwfn,
void *pwfn_arg)
{
SEC_PKCS7ContentInfo *cinfo;
long cipher;
SECOidTag encalg;
int keysize;
int mapi, rci;
cipher = smime_choose_cipher(scert, rcerts);
if (cipher < 0)
return NULL;
mapi = smime_mapi_by_cipher(cipher);
if (mapi < 0)
return NULL;
/*
* XXX This is stretching it -- CreateEnvelopedData should probably
* take a cipher itself of some sort, because we cannot know what the
* future will bring in terms of parameters for each type of algorithm.
* For example, just an algorithm and keysize is *not* sufficient to
* fully specify the usage of RC5 (which also needs to know rounds and
* block size). Work this out into a better API!
*/
encalg = smime_cipher_maps[mapi].algtag;
keysize = smime_keysize_by_cipher(cipher);
if (keysize < 0)
return NULL;
cinfo = SEC_PKCS7CreateEnvelopedData(scert, certUsageEmailRecipient,
certdb, encalg, keysize,
pwfn, pwfn_arg);
if (cinfo == NULL)
return NULL;
for (rci = 0; rcerts[rci] != NULL; rci++) {
if (rcerts[rci] == scert)
continue;
if (SEC_PKCS7AddRecipient(cinfo, rcerts[rci], certUsageEmailRecipient,
NULL) != SECSuccess) {
SEC_PKCS7DestroyContentInfo(cinfo);
return NULL;
}
}
return cinfo;
}
static smime_capability **smime_capabilities;
static SECItem *smime_encoded_caps;
static SECStatus
smime_init_caps(void)
{
smime_capability *cap;
smime_cipher_map *map;
SECOidData *oiddata;
SECStatus rv;
int i;
if (smime_encoded_caps != NULL && (!smime_prefs_changed))
return SECSuccess;
if (smime_encoded_caps != NULL) {
SECITEM_FreeItem(smime_encoded_caps, PR_TRUE);
smime_encoded_caps = NULL;
}
if (smime_capabilities == NULL) {
smime_capabilities = (smime_capability **)PORT_ZAlloc(
(smime_symmetric_count + 1) * sizeof(smime_capability *));
if (smime_capabilities == NULL)
return SECFailure;
}
rv = SECFailure;
/*
The process of creating the encoded PKCS7 cipher capability list
involves two basic steps:
(a) Convert our internal representation of cipher preferences
(smime_prefs) into an array containing cipher OIDs and
parameter data (smime_capabilities). This step is
performed here.
(b) Encode, using ASN.1, the cipher information in
smime_capabilities, leaving the encoded result in
smime_encoded_caps.
(In the process of performing (a), Lisa put in some optimizations
which allow us to avoid needlessly re-populating elements in
smime_capabilities as we walk through smime_prefs.)
*/
for (i = 0; i < smime_current_pref_index; i++) {
int mapi;
/* Get the next cipher preference in smime_prefs. */
mapi = smime_mapi_by_cipher(smime_prefs[i]);
if (mapi < 0)
break;
/* Find the corresponding entry in the cipher map. */
PORT_Assert(mapi < smime_symmetric_count);
map = &(smime_cipher_maps[mapi]);
/*
* Convert the next preference found in smime_prefs into an
* smime_capability.
*/
cap = smime_capabilities[i];
if (cap == NULL) {
cap = (smime_capability *)PORT_ZAlloc(sizeof(smime_capability));
if (cap == NULL)
break;
smime_capabilities[i] = cap;
} else if (cap->cipher == smime_prefs[i]) {
continue; /* no change to this one */
}
cap->capIDTag = map->algtag;
oiddata = SECOID_FindOIDByTag(map->algtag);
if (oiddata == NULL)
break;
if (cap->capabilityID.data != NULL) {
SECITEM_FreeItem(&(cap->capabilityID), PR_FALSE);
cap->capabilityID.data = NULL;
cap->capabilityID.len = 0;
}
rv = SECITEM_CopyItem(NULL, &(cap->capabilityID), &(oiddata->oid));
if (rv != SECSuccess)
break;
if (map->parms == NULL) {
cap->parameters.data = NULL;
cap->parameters.len = 0;
} else {
cap->parameters.data = map->parms->data;
cap->parameters.len = map->parms->len;
}
cap->cipher = smime_prefs[i];
}
if (i != smime_current_pref_index)
return rv;
while (i < smime_symmetric_count) {
cap = smime_capabilities[i];
if (cap != NULL) {
SECITEM_FreeItem(&(cap->capabilityID), PR_FALSE);
PORT_Free(cap);
}
smime_capabilities[i] = NULL;
i++;
}
smime_capabilities[i] = NULL;
smime_encoded_caps = SEC_ASN1EncodeItem(NULL, NULL, &smime_capabilities,
smime_capabilities_template);
if (smime_encoded_caps == NULL)
return SECFailure;
return SECSuccess;
}
static SECStatus
smime_add_profile(CERTCertificate *cert, SEC_PKCS7ContentInfo *cinfo)
{
PORT_Assert(smime_prefs_complete);
if (!smime_prefs_complete)
return SECFailure;
/* For that matter, if capabilities haven't been initialized yet,
do so now. */
if (smime_encoded_caps == NULL || smime_prefs_changed) {
SECStatus rv;
rv = smime_init_caps();
if (rv != SECSuccess)
return rv;
PORT_Assert(smime_encoded_caps != NULL);
}
return SEC_PKCS7AddSignedAttribute(cinfo, SEC_OID_PKCS9_SMIME_CAPABILITIES,
smime_encoded_caps);
}
/*
* Start an S/MIME signing context.
*
* "scert" is the cert that will be used to sign the data. It will be
* checked for validity.
*
* "ecert" is the signer's encryption cert. If it is different from
* scert, then it will be included in the signed message so that the
* recipient can save it for future encryptions.
*
* "certdb" is the cert database to use for verifying the cert.
* It can be NULL if a default database is available (like in the client).
*
* "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
* XXX There should be SECMIME functions for hashing, or the hashing should
* be built into this interface, which we would like because we would
* support more smartcards that way, and then this argument should go away.)
*
* "digest" is the actual digest of the data. It must be provided in
* the case of detached data or NULL if the content will be included.
*
* This function already does all of the stuff specific to S/MIME protocol
* and local policy; the return value just needs to be passed to
* SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
* and finally to SEC_PKCS7DestroyContentInfo().
*
* An error results in a return value of NULL and an error set.
* (Retrieve specific errors via PORT_GetError()/XP_GetError().)
*/
SEC_PKCS7ContentInfo *
SECMIME_CreateSigned(CERTCertificate *scert,
CERTCertificate *ecert,
CERTCertDBHandle *certdb,
SECOidTag digestalg,
SECItem *digest,
SECKEYGetPasswordKey pwfn,
void *pwfn_arg)
{
SEC_PKCS7ContentInfo *cinfo;
SECStatus rv;
/* See note in header comment above about digestalg. */
/* Doesn't explain this. PORT_Assert (digestalg == SEC_OID_SHA1); */
cinfo = SEC_PKCS7CreateSignedData(scert, certUsageEmailSigner,
certdb, digestalg, digest,
pwfn, pwfn_arg);
if (cinfo == NULL)
return NULL;
if (SEC_PKCS7IncludeCertChain(cinfo, NULL) != SECSuccess) {
SEC_PKCS7DestroyContentInfo(cinfo);
return NULL;
}
/* if the encryption cert and the signing cert differ, then include
* the encryption cert too.
*/
/* it is ok to compare the pointers since we ref count, and the same
* cert will always have the same pointer
*/
if ((ecert != NULL) && (ecert != scert)) {
rv = SEC_PKCS7AddCertificate(cinfo, ecert);
if (rv != SECSuccess) {
SEC_PKCS7DestroyContentInfo(cinfo);
return NULL;
}
}
/*
* Add the signing time. But if it fails for some reason,
* may as well not give up altogether -- just assert.
*/
rv = SEC_PKCS7AddSigningTime(cinfo);
PORT_Assert(rv == SECSuccess);
/*
* Add the email profile. Again, if it fails for some reason,
* may as well not give up altogether -- just assert.
*/
rv = smime_add_profile(ecert, cinfo);
PORT_Assert(rv == SECSuccess);
return cinfo;
}

View file

@ -0,0 +1,160 @@
/* 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/. */
/*
* Header file for routines specific to S/MIME. Keep things that are pure
* pkcs7 out of here; this is for S/MIME policy, S/MIME interoperability, etc.
*/
#ifndef _SECMIME_H_
#define _SECMIME_H_ 1
#include "secpkcs7.h"
/************************************************************************/
SEC_BEGIN_PROTOS
/*
* Initialize the local recording of the user S/MIME cipher preferences.
* This function is called once for each cipher, the order being
* important (first call records greatest preference, and so on).
* When finished, it is called with a "which" of CIPHER_FAMILID_MASK.
* If the function is called again after that, it is assumed that
* the preferences are being reset, and the old preferences are
* discarded.
*
* XXX This is for a particular user, and right now the storage is
* XXX local, static. The preference should be stored elsewhere to allow
* XXX for multiple uses of one library? How does SSL handle this;
* XXX it has something similar?
*
* - The "which" values are defined in ciferfam.h (the SMIME_* values,
* for example SMIME_DES_CBC_56).
* - If "on" is non-zero then the named cipher is enabled, otherwise
* it is disabled. (It is not necessary to call the function for
* ciphers that are disabled, however, as that is the default.)
*
* If the cipher preference is successfully recorded, SECSuccess
* is returned. Otherwise SECFailure is returned. The only errors
* are due to failure allocating memory or bad parameters/calls:
* SEC_ERROR_XXX ("which" is not in the S/MIME cipher family)
* SEC_ERROR_XXX (function is being called more times than there
* are known/expected ciphers)
*/
extern SECStatus SECMIME_EnableCipher(long which, int on);
/*
* Initialize the local recording of the S/MIME policy.
* This function is called to enable/disable a particular cipher.
* (S/MIME encryption or decryption using a particular cipher is only
* allowed if that cipher is currently enabled.) At startup, all S/MIME
* ciphers are disabled. From that point, this function can be called
* to enable a cipher -- it is not necessary to call this to disable
* a cipher unless that cipher was previously, explicitly enabled via
* this function.
*
* XXX This is for a the current module, I think, so local, static storage
* XXX is okay. Is that correct, or could multiple uses of the same
* XXX library expect to operate under different policies?
*
* - The "which" values are defined in ciferfam.h (the SMIME_* values,
* for example SMIME_DES_CBC_56).
* - If "on" is non-zero then the named cipher is enabled, otherwise
* it is disabled.
*
* If the cipher is successfully enabled/disabled, SECSuccess is
* returned. Otherwise SECFailure is returned. The only errors
* are due to bad parameters:
* SEC_ERROR_XXX ("which" is not in the S/MIME cipher family)
* SEC_ERROR_XXX ("which" exceeds expected maximum cipher; this is
* really an internal error)
*/
extern SECStatus SECMIME_SetPolicy(long which, int on);
/*
* Does the current policy allow S/MIME decryption of this particular
* algorithm and keysize?
*/
extern PRBool SECMIME_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key);
/*
* Does the current policy allow *any* S/MIME encryption (or decryption)?
*
* This tells whether or not *any* S/MIME encryption can be done,
* according to policy. Callers may use this to do nicer user interface
* (say, greying out a checkbox so a user does not even try to encrypt
* a message when they are not allowed to) or for any reason they want
* to check whether S/MIME encryption (or decryption, for that matter)
* may be done.
*
* It takes no arguments. The return value is a simple boolean:
* PR_TRUE means encryption (or decryption) is *possible*
* (but may still fail due to other reasons, like because we cannot
* find all the necessary certs, etc.; PR_TRUE is *not* a guarantee)
* PR_FALSE means encryption (or decryption) is not permitted
*
* There are no errors from this routine.
*/
extern PRBool SECMIME_EncryptionPossible(void);
/*
* Start an S/MIME encrypting context.
*
* "scert" is the cert for the sender. It will be checked for validity.
* "rcerts" are the certs for the recipients. They will also be checked.
*
* "certdb" is the cert database to use for verifying the certs.
* It can be NULL if a default database is available (like in the client).
*
* This function already does all of the stuff specific to S/MIME protocol
* and local policy; the return value just needs to be passed to
* SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
* and finally to SEC_PKCS7DestroyContentInfo().
*
* An error results in a return value of NULL and an error set.
* (Retrieve specific errors via PORT_GetError()/XP_GetError().)
*/
extern SEC_PKCS7ContentInfo *SECMIME_CreateEncrypted(CERTCertificate *scert,
CERTCertificate **rcerts,
CERTCertDBHandle *certdb,
SECKEYGetPasswordKey pwfn,
void *pwfn_arg);
/*
* Start an S/MIME signing context.
*
* "scert" is the cert that will be used to sign the data. It will be
* checked for validity.
*
* "certdb" is the cert database to use for verifying the cert.
* It can be NULL if a default database is available (like in the client).
*
* "digestalg" names the digest algorithm. (It should be SEC_OID_SHA1;
* XXX There should be SECMIME functions for hashing, or the hashing should
* be built into this interface, which we would like because we would
* support more smartcards that way, and then this argument should go away.)
*
* "digest" is the actual digest of the data. It must be provided in
* the case of detached data or NULL if the content will be included.
*
* This function already does all of the stuff specific to S/MIME protocol
* and local policy; the return value just needs to be passed to
* SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
* and finally to SEC_PKCS7DestroyContentInfo().
*
* An error results in a return value of NULL and an error set.
* (Retrieve specific errors via PORT_GetError()/XP_GetError().)
*/
extern SEC_PKCS7ContentInfo *SECMIME_CreateSigned(CERTCertificate *scert,
CERTCertificate *ecert,
CERTCertDBHandle *certdb,
SECOidTag digestalg,
SECItem *digest,
SECKEYGetPasswordKey pwfn,
void *pwfn_arg);
/************************************************************************/
SEC_END_PROTOS
#endif /* _SECMIME_H_ */

View file

@ -0,0 +1,606 @@
/* 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/. */
/*
* Interface to the PKCS7 implementation.
*/
#ifndef _SECPKCS7_H_
#define _SECPKCS7_H_
#include "seccomon.h"
#include "secoidt.h"
#include "certt.h"
#include "keyt.h"
#include "hasht.h"
#include "pkcs7t.h"
extern const SEC_ASN1Template sec_PKCS7ContentInfoTemplate[];
/************************************************************************/
SEC_BEGIN_PROTOS
/************************************************************************
* Miscellaneous
************************************************************************/
/*
* Returns the content type of the given contentInfo.
*/
extern SECOidTag SEC_PKCS7ContentType(SEC_PKCS7ContentInfo *cinfo);
/*
* Destroy a PKCS7 contentInfo and all of its sub-pieces.
*/
extern void SEC_PKCS7DestroyContentInfo(SEC_PKCS7ContentInfo *contentInfo);
/*
* Copy a PKCS7 contentInfo. A Destroy is needed on *each* copy.
*/
extern SEC_PKCS7ContentInfo *
SEC_PKCS7CopyContentInfo(SEC_PKCS7ContentInfo *contentInfo);
/*
* Return a pointer to the actual content. In the case of those types
* which are encrypted, this returns the *plain* content.
*/
extern SECItem *SEC_PKCS7GetContent(SEC_PKCS7ContentInfo *cinfo);
/************************************************************************
* PKCS7 Decoding, Verification, etc..
************************************************************************/
extern SEC_PKCS7DecoderContext *
SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback callback,
void *callback_arg,
SECKEYGetPasswordKey pwfn, void *pwfn_arg,
SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb,
void *decrypt_key_cb_arg,
SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb);
extern SECStatus
SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx,
const char *buf, unsigned long len);
extern SEC_PKCS7ContentInfo *
SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx);
/* Abort the underlying ASN.1 stream & set an error */
void SEC_PKCS7DecoderAbort(SEC_PKCS7DecoderContext *p7dcx, int error);
extern SEC_PKCS7ContentInfo *
SEC_PKCS7DecodeItem(SECItem *p7item,
SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
SECKEYGetPasswordKey pwfn, void *pwfn_arg,
SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb,
void *decrypt_key_cb_arg,
SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb);
extern PRBool SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo);
/* checks to see if the contents of the content info is
* empty. it so, PR_TRUE is returned. PR_FALSE, otherwise.
*
* minLen is used to specify a minimum size. if content size <= minLen,
* content is assumed empty.
*/
extern PRBool
SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen);
extern PRBool SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo);
/*
* If the PKCS7 content has a signature (not just *could* have a signature)
* return true; false otherwise. This can/should be called before calling
* VerifySignature, which will always indicate failure if no signature is
* present, but that does not mean there even was a signature!
* Note that the content itself can be empty (detached content was sent
* another way); it is the presence of the signature that matters.
*/
extern PRBool SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo);
/*
* SEC_PKCS7VerifySignature
* Look at a PKCS7 contentInfo and check if the signature is good.
* The verification checks that the signing cert is valid and trusted
* for the purpose specified by "certusage".
*
* In addition, if "keepcerts" is true, add any new certificates found
* into our local database.
*/
extern PRBool SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo,
SECCertUsage certusage,
PRBool keepcerts);
/*
* SEC_PKCS7VerifyDetachedSignature
* Look at a PKCS7 contentInfo and check if the signature matches
* a passed-in digest (calculated, supposedly, from detached contents).
* The verification checks that the signing cert is valid and trusted
* for the purpose specified by "certusage".
*
* In addition, if "keepcerts" is true, add any new certificates found
* into our local database.
*/
extern PRBool SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
SECCertUsage certusage,
const SECItem *detached_digest,
HASH_HashType digest_type,
PRBool keepcerts);
/*
* SEC_PKCS7VerifyDetachedSignatureAtTime
* Look at a PKCS7 contentInfo and check if the signature matches
* a passed-in digest (calculated, supposedly, from detached contents).
* The verification checks that the signing cert is valid and trusted
* for the purpose specified by "certusage" at time "atTime".
*
* In addition, if "keepcerts" is true, add any new certificates found
* into our local database.
*/
extern PRBool
SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo,
SECCertUsage certusage,
const SECItem *detached_digest,
HASH_HashType digest_type,
PRBool keepcerts,
PRTime atTime);
/*
* SEC_PKCS7GetSignerCommonName, SEC_PKCS7GetSignerEmailAddress
* The passed-in contentInfo is espected to be Signed, and these
* functions return the specified portion of the full signer name.
*
* Returns a pointer to allocated memory, which must be freed.
* A NULL return value is an error.
*/
extern char *SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo);
extern char *SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo);
/*
* Return the the signing time, in UTCTime format, of a PKCS7 contentInfo.
*/
extern SECItem *SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo);
/************************************************************************
* PKCS7 Creation and Encoding.
************************************************************************/
/*
* Start a PKCS7 signing context.
*
* "cert" is the cert that will be used to sign the data. It will be
* checked for validity.
*
* "certusage" describes the signing usage (e.g. certUsageEmailSigner)
* XXX Maybe SECCertUsage should be split so that our caller just says
* "email" and *we* add the "signing" part -- otherwise our caller
* could be lying about the usage; we do not want to allow encryption
* certs for signing or vice versa.
*
* "certdb" is the cert database to use for verifying the cert.
* It can be NULL if a default database is available (like in the client).
*
* "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
*
* "digest" is the actual digest of the data. It must be provided in
* the case of detached data or NULL if the content will be included.
*
* The return value can be passed to functions which add things to
* it like attributes, then eventually to SEC_PKCS7Encode() or to
* SEC_PKCS7EncoderStart() to create the encoded data, and finally to
* SEC_PKCS7DestroyContentInfo().
*
* An error results in a return value of NULL and an error set.
* (Retrieve specific errors via PORT_GetError()/XP_GetError().)
*/
extern SEC_PKCS7ContentInfo *
SEC_PKCS7CreateSignedData(CERTCertificate *cert,
SECCertUsage certusage,
CERTCertDBHandle *certdb,
SECOidTag digestalg,
SECItem *digest,
SECKEYGetPasswordKey pwfn, void *pwfn_arg);
/*
* Create a PKCS7 certs-only container.
*
* "cert" is the (first) cert that will be included.
*
* "include_chain" specifies whether the entire chain for "cert" should
* be included.
*
* "certdb" is the cert database to use for finding the chain.
* It can be NULL in when "include_chain" is false, or when meaning
* use the default database.
*
* More certs and chains can be added via AddCertficate and AddCertChain.
*
* An error results in a return value of NULL and an error set.
* (Retrieve specific errors via PORT_GetError()/XP_GetError().)
*/
extern SEC_PKCS7ContentInfo *
SEC_PKCS7CreateCertsOnly(CERTCertificate *cert,
PRBool include_chain,
CERTCertDBHandle *certdb);
/*
* Start a PKCS7 enveloping context.
*
* "cert" is the cert for the recipient. It will be checked for validity.
*
* "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
* XXX Maybe SECCertUsage should be split so that our caller just says
* "email" and *we* add the "recipient" part -- otherwise our caller
* could be lying about the usage; we do not want to allow encryption
* certs for signing or vice versa.
*
* "certdb" is the cert database to use for verifying the cert.
* It can be NULL if a default database is available (like in the client).
*
* "encalg" specifies the bulk encryption algorithm to use (e.g. SEC_OID_RC2).
*
* "keysize" specifies the bulk encryption key size, in bits.
*
* The return value can be passed to functions which add things to
* it like more recipients, then eventually to SEC_PKCS7Encode() or to
* SEC_PKCS7EncoderStart() to create the encoded data, and finally to
* SEC_PKCS7DestroyContentInfo().
*
* An error results in a return value of NULL and an error set.
* (Retrieve specific errors via PORT_GetError()/XP_GetError().)
*/
extern SEC_PKCS7ContentInfo *
SEC_PKCS7CreateEnvelopedData(CERTCertificate *cert,
SECCertUsage certusage,
CERTCertDBHandle *certdb,
SECOidTag encalg,
int keysize,
SECKEYGetPasswordKey pwfn, void *pwfn_arg);
/*
* XXX There will be a similar routine for creating signedAndEnvelopedData.
* But its parameters will be different and I have no plans to implement
* it any time soon because we have no current need for it.
*/
/*
* Create an empty PKCS7 data content info.
*
* An error results in a return value of NULL and an error set.
* (Retrieve specific errors via PORT_GetError()/XP_GetError().)
*/
extern SEC_PKCS7ContentInfo *SEC_PKCS7CreateData(void);
/*
* Create an empty PKCS7 encrypted content info.
*
* "algorithm" specifies the bulk encryption algorithm to use.
*
* An error results in a return value of NULL and an error set.
* (Retrieve specific errors via PORT_GetError()/XP_GetError().)
*/
extern SEC_PKCS7ContentInfo *
SEC_PKCS7CreateEncryptedData(SECOidTag algorithm, int keysize,
SECKEYGetPasswordKey pwfn, void *pwfn_arg);
/*
* All of the following things return SECStatus to signal success or failure.
* Failure should have a more specific error status available via
* PORT_GetError()/XP_GetError().
*/
/*
* Add the specified attribute to the authenticated (i.e. signed) attributes
* of "cinfo" -- "oidtag" describes the attribute and "value" is the
* value to be associated with it. NOTE! "value" must already be encoded;
* no interpretation of "oidtag" is done. Also, it is assumed that this
* signedData has only one signer -- if we ever need to add attributes
* when there is more than one signature, we need a way to specify *which*
* signature should get the attribute.
*
* XXX Technically, a signed attribute can have multiple values; if/when
* we ever need to support an attribute which takes multiple values, we
* either need to change this interface or create an AddSignedAttributeValue
* which can be called subsequently, and would then append a value.
*
* "cinfo" should be of type signedData (the only kind of pkcs7 data
* that is allowed authenticated attributes); SECFailure will be returned
* if it is not.
*/
extern SECStatus SEC_PKCS7AddSignedAttribute(SEC_PKCS7ContentInfo *cinfo,
SECOidTag oidtag,
SECItem *value);
/*
* Add "cert" and its entire chain to the set of certs included in "cinfo".
*
* "certdb" is the cert database to use for finding the chain.
* It can be NULL, meaning use the default database.
*
* "cinfo" should be of type signedData or signedAndEnvelopedData;
* SECFailure will be returned if it is not.
*/
extern SECStatus SEC_PKCS7AddCertChain(SEC_PKCS7ContentInfo *cinfo,
CERTCertificate *cert,
CERTCertDBHandle *certdb);
/*
* Add "cert" to the set of certs included in "cinfo".
*
* "cinfo" should be of type signedData or signedAndEnvelopedData;
* SECFailure will be returned if it is not.
*/
extern SECStatus SEC_PKCS7AddCertificate(SEC_PKCS7ContentInfo *cinfo,
CERTCertificate *cert);
/*
* Add another recipient to an encrypted message.
*
* "cinfo" should be of type envelopedData or signedAndEnvelopedData;
* SECFailure will be returned if it is not.
*
* "cert" is the cert for the recipient. It will be checked for validity.
*
* "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
* XXX Maybe SECCertUsage should be split so that our caller just says
* "email" and *we* add the "recipient" part -- otherwise our caller
* could be lying about the usage; we do not want to allow encryption
* certs for signing or vice versa.
*
* "certdb" is the cert database to use for verifying the cert.
* It can be NULL if a default database is available (like in the client).
*/
extern SECStatus SEC_PKCS7AddRecipient(SEC_PKCS7ContentInfo *cinfo,
CERTCertificate *cert,
SECCertUsage certusage,
CERTCertDBHandle *certdb);
/*
* Add the signing time to the authenticated (i.e. signed) attributes
* of "cinfo". This is expected to be included in outgoing signed
* messages for email (S/MIME) but is likely useful in other situations.
*
* This should only be added once; a second call will either do
* nothing or replace an old signing time with a newer one.
*
* XXX This will probably just shove the current time into "cinfo"
* but it will not actually get signed until the entire item is
* processed for encoding. Is this (expected to be small) delay okay?
*
* "cinfo" should be of type signedData (the only kind of pkcs7 data
* that is allowed authenticated attributes); SECFailure will be returned
* if it is not.
*/
extern SECStatus SEC_PKCS7AddSigningTime(SEC_PKCS7ContentInfo *cinfo);
/*
* Add the signer's symmetric capabilities to the authenticated
* (i.e. signed) attributes of "cinfo". This is expected to be
* included in outgoing signed messages for email (S/MIME).
*
* This can only be added once; a second call will return SECFailure.
*
* "cinfo" should be of type signedData or signedAndEnvelopedData;
* SECFailure will be returned if it is not.
*/
extern SECStatus SEC_PKCS7AddSymmetricCapabilities(SEC_PKCS7ContentInfo *cinfo);
/*
* Mark that the signer's certificate and its issuing chain should
* be included in the encoded data. This is expected to be used
* in outgoing signed messages for email (S/MIME).
*
* "certdb" is the cert database to use for finding the chain.
* It can be NULL, meaning use the default database.
*
* "cinfo" should be of type signedData or signedAndEnvelopedData;
* SECFailure will be returned if it is not.
*/
extern SECStatus SEC_PKCS7IncludeCertChain(SEC_PKCS7ContentInfo *cinfo,
CERTCertDBHandle *certdb);
/*
* Set the content; it will be included and also hashed and/or encrypted
* as appropriate. This is for in-memory content (expected to be "small")
* that will be included in the PKCS7 object. All others should stream the
* content through when encoding (see SEC_PKCS7Encoder{Start,Update,Finish}).
*
* "buf" points to data of length "len"; it will be copied.
*/
extern SECStatus SEC_PKCS7SetContent(SEC_PKCS7ContentInfo *cinfo,
const char *buf, unsigned long len);
/*
* Encode a PKCS7 object, in one shot. All necessary components
* of the object must already be specified. Either the data has
* already been included (via SetContent), or the data is detached,
* or there is no data at all (certs-only).
*
* "cinfo" specifies the object to be encoded.
*
* "outputfn" is where the encoded bytes will be passed.
*
* "outputarg" is an opaque argument to the above callback.
*
* "bulkkey" specifies the bulk encryption key to use. This argument
* can be NULL if no encryption is being done, or if the bulk key should
* be generated internally (usually the case for EnvelopedData but never
* for EncryptedData, which *must* provide a bulk encryption key).
*
* "pwfn" is a callback for getting the password which protects the
* private key of the signer. This argument can be NULL if it is known
* that no signing is going to be done.
*
* "pwfnarg" is an opaque argument to the above callback.
*/
extern SECStatus SEC_PKCS7Encode(SEC_PKCS7ContentInfo *cinfo,
SEC_PKCS7EncoderOutputCallback outputfn,
void *outputarg,
PK11SymKey *bulkkey,
SECKEYGetPasswordKey pwfn,
void *pwfnarg);
/*
* Encode a PKCS7 object, in one shot. All necessary components
* of the object must already be specified. Either the data has
* already been included (via SetContent), or the data is detached,
* or there is no data at all (certs-only). The output, rather than
* being passed to an output function as is done above, is all put
* into a SECItem.
*
* "pool" specifies a pool from which to allocate the result.
* It can be NULL, in which case memory is allocated generically.
*
* "dest" specifies a SECItem in which to put the result data.
* It can be NULL, in which case the entire item is allocated, too.
*
* "cinfo" specifies the object to be encoded.
*
* "bulkkey" specifies the bulk encryption key to use. This argument
* can be NULL if no encryption is being done, or if the bulk key should
* be generated internally (usually the case for EnvelopedData but never
* for EncryptedData, which *must* provide a bulk encryption key).
*
* "pwfn" is a callback for getting the password which protects the
* private key of the signer. This argument can be NULL if it is known
* that no signing is going to be done.
*
* "pwfnarg" is an opaque argument to the above callback.
*/
extern SECItem *SEC_PKCS7EncodeItem(PLArenaPool *pool,
SECItem *dest,
SEC_PKCS7ContentInfo *cinfo,
PK11SymKey *bulkkey,
SECKEYGetPasswordKey pwfn,
void *pwfnarg);
/*
* For those who want to simply point to the pkcs7 contentInfo ASN.1
* template, and *not* call the encoding functions directly, the
* following function can be used -- after it is called, the entire
* PKCS7 contentInfo is ready to be encoded.
*/
extern SECStatus SEC_PKCS7PrepareForEncode(SEC_PKCS7ContentInfo *cinfo,
PK11SymKey *bulkkey,
SECKEYGetPasswordKey pwfn,
void *pwfnarg);
/*
* Start the process of encoding a PKCS7 object. The first part of
* the encoded object will be passed to the output function right away;
* after that it is expected that SEC_PKCS7EncoderUpdate will be called,
* streaming in the actual content that is getting included as well as
* signed or encrypted (or both).
*
* "cinfo" specifies the object to be encoded.
*
* "outputfn" is where the encoded bytes will be passed.
*
* "outputarg" is an opaque argument to the above callback.
*
* "bulkkey" specifies the bulk encryption key to use. This argument
* can be NULL if no encryption is being done, or if the bulk key should
* be generated internally (usually the case for EnvelopedData but never
* for EncryptedData, which *must* provide a bulk encryption key).
*
* Returns an object to be passed to EncoderUpdate and EncoderFinish.
*/
extern SEC_PKCS7EncoderContext *
SEC_PKCS7EncoderStart(SEC_PKCS7ContentInfo *cinfo,
SEC_PKCS7EncoderOutputCallback outputfn,
void *outputarg,
PK11SymKey *bulkkey);
/*
* Encode more contents, hashing and/or encrypting along the way.
*/
extern SECStatus SEC_PKCS7EncoderUpdate(SEC_PKCS7EncoderContext *p7ecx,
const char *buf,
unsigned long len);
/*
* No more contents; finish the signature creation, if appropriate,
* and then the encoding.
*
* "pwfn" is a callback for getting the password which protects the
* signer's private key. This argument can be NULL if it is known
* that no signing is going to be done.
*
* "pwfnarg" is an opaque argument to the above callback.
*/
extern SECStatus SEC_PKCS7EncoderFinish(SEC_PKCS7EncoderContext *p7ecx,
SECKEYGetPasswordKey pwfn,
void *pwfnarg);
/* Abort the underlying ASN.1 stream & set an error */
void SEC_PKCS7EncoderAbort(SEC_PKCS7EncoderContext *p7dcx, int error);
/* retrieve the algorithm ID used to encrypt the content info
* for encrypted and enveloped data. The SECAlgorithmID pointer
* returned needs to be freed as it is a copy of the algorithm
* id in the content info.
*/
extern SECAlgorithmID *
SEC_PKCS7GetEncryptionAlgorithm(SEC_PKCS7ContentInfo *cinfo);
/* 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.
*/
extern SECStatus
SEC_PKCS7EncryptContents(PLArenaPool *poolp,
SEC_PKCS7ContentInfo *cinfo,
SECItem *key,
void *wincx);
/* 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.
*/
extern SECStatus
SEC_PKCS7DecryptContents(PLArenaPool *poolp,
SEC_PKCS7ContentInfo *cinfo,
SECItem *key,
void *wincx);
/* retrieve the certificate list from the content info. the list
* is a pointer to the list in the content info. this should not
* be deleted or freed in any way short of calling
* SEC_PKCS7DestroyContentInfo
*/
extern SECItem **
SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo *cinfo);
/* Returns the key length (in bits) of the algorithm used to encrypt
this object. Returns 0 if it's not encrypted, or the key length is
irrelevant. */
extern int
SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo *cinfo);
/************************************************************************/
SEC_END_PROTOS
#endif /* _SECPKCS7_H_ */