mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-04 14:27:30 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
48
security/nss/lib/pkcs7/Makefile
Normal file
48
security/nss/lib/pkcs7/Makefile
Normal 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). #
|
||||
#######################################################################
|
||||
|
||||
|
||||
|
||||
528
security/nss/lib/pkcs7/certread.c
Normal file
528
security/nss/lib/pkcs7/certread.c
Normal 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);
|
||||
}
|
||||
14
security/nss/lib/pkcs7/config.mk
Normal file
14
security/nss/lib/pkcs7/config.mk
Normal 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 =
|
||||
33
security/nss/lib/pkcs7/exports.gyp
Normal file
33
security/nss/lib/pkcs7/exports.gyp
Normal 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'
|
||||
}
|
||||
}
|
||||
33
security/nss/lib/pkcs7/manifest.mn
Normal file
33
security/nss/lib/pkcs7/manifest.mn
Normal 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
|
||||
663
security/nss/lib/pkcs7/p7common.c
Normal file
663
security/nss/lib/pkcs7/p7common.c
Normal 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;
|
||||
}
|
||||
1247
security/nss/lib/pkcs7/p7create.c
Normal file
1247
security/nss/lib/pkcs7/p7create.c
Normal file
File diff suppressed because it is too large
Load diff
1914
security/nss/lib/pkcs7/p7decode.c
Normal file
1914
security/nss/lib/pkcs7/p7decode.c
Normal file
File diff suppressed because it is too large
Load diff
1079
security/nss/lib/pkcs7/p7encode.c
Normal file
1079
security/nss/lib/pkcs7/p7encode.c
Normal file
File diff suppressed because it is too large
Load diff
1310
security/nss/lib/pkcs7/p7local.c
Normal file
1310
security/nss/lib/pkcs7/p7local.c
Normal file
File diff suppressed because it is too large
Load diff
137
security/nss/lib/pkcs7/p7local.h
Normal file
137
security/nss/lib/pkcs7/p7local.h
Normal 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_ */
|
||||
29
security/nss/lib/pkcs7/pkcs7.gyp
Normal file
29
security/nss/lib/pkcs7/pkcs7.gyp
Normal 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'
|
||||
}
|
||||
}
|
||||
233
security/nss/lib/pkcs7/pkcs7t.h
Normal file
233
security/nss/lib/pkcs7/pkcs7t.h
Normal 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_ */
|
||||
800
security/nss/lib/pkcs7/secmime.c
Normal file
800
security/nss/lib/pkcs7/secmime.c
Normal 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;
|
||||
}
|
||||
160
security/nss/lib/pkcs7/secmime.h
Normal file
160
security/nss/lib/pkcs7/secmime.h
Normal 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_ */
|
||||
606
security/nss/lib/pkcs7/secpkcs7.h
Normal file
606
security/nss/lib/pkcs7/secpkcs7.h
Normal 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_ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue