Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/security/nss/lib/smime/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 35 kB image not shown  

Quelle  cmssiginfo.c   Sprache: C

 
/* 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/. */


/*
 * CMS signerInfo methods.
 */


#include "cmslocal.h"

#include "cert.h"
#include "keyhi.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
#include "pk11func.h"
#include "prtime.h"
#include "secerr.h"
#include "secder.h"
#include "cryptohi.h"

#include "smime.h"

/* =============================================================================
 * SIGNERINFO
 */

NSSCMSSignerInfo *
nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type,
                         CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey,
                         SECKEYPrivateKey *signingKey, SECOidTag digestalgtag);

NSSCMSSignerInfo *
NSS_CMSSignerInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg, SECItem *subjKeyID,
                                      SECKEYPublicKey *pubKey,
                                      SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
{
    return nss_cmssignerinfo_create(cmsg, NSSCMSSignerID_SubjectKeyID, NULL,
                                    subjKeyID, pubKey, signingKey, digestalgtag);
}

NSSCMSSignerInfo *
NSS_CMSSignerInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert, SECOidTag digestalgtag)
{
    return nss_cmssignerinfo_create(cmsg, NSSCMSSignerID_IssuerSN, cert, NULL,
                                    NULL, NULL, digestalgtag);
}

NSSCMSSignerInfo *
nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type,
                         CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey,
                         SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
{
    void *mark;
    NSSCMSSignerInfo *signerinfo;
    int version;
    PLArenaPool *poolp;
    SECStatus rv;

    poolp = cmsg->poolp;

    mark = PORT_ArenaMark(poolp);

    signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo));
    if (signerinfo == NULL) {
        PORT_ArenaRelease(poolp, mark);
        return NULL;
    }

    signerinfo->cmsg = cmsg;

    switch (type) {
        case NSSCMSSignerID_IssuerSN:
            signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_IssuerSN;
            if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL)
                goto loser;
            if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL)
                goto loser;
            break;
        case NSSCMSSignerID_SubjectKeyID:
            signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_SubjectKeyID;
            PORT_Assert(subjKeyID);
            if (!subjKeyID)
                goto loser;

            signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
            rv = SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
                                  subjKeyID);
            if (rv != SECSuccess) {
                goto loser;
            }
            signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey);
            if (!signerinfo->signingKey)
                goto loser;
            signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
            if (!signerinfo->pubKey)
                goto loser;
            break;
        default:
            goto loser;
    }

    /* set version right now */
    version = NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN;
    /* RFC2630 5.3 "version is the syntax version number. If the .... " */
    if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID)
        version = NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY;
    (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version);

    if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess)
        goto loser;

    PORT_ArenaUnmark(poolp, mark);
    return signerinfo;

loser:
    PORT_ArenaRelease(poolp, mark);
    return NULL;
}

/*
 * NSS_CMSSignerInfo_Destroy - destroy a SignerInfo data structure
 */

void
NSS_CMSSignerInfo_Destroy(NSSCMSSignerInfo *si)
{
    if (si->cert != NULL)
        CERT_DestroyCertificate(si->cert);

    if (si->certList != NULL)
        CERT_DestroyCertificateList(si->certList);

    /* XXX storage ??? */
}
static SECOidTag
NSS_CMSSignerInfo_GetSignatureAlgorithmOidTag(KeyType keyType,
                                              SECOidTag pubkAlgTag,
                                              SECOidTag signAlgTag)
{
    switch (keyType) {
        case rsaKey:
            return pubkAlgTag;
        case rsaPssKey:
        case dsaKey:
        case ecKey:
            return signAlgTag;
        default:
            return SEC_OID_UNKNOWN;
    }
}

/*
 * NSS_CMSSignerInfo_Sign - sign something
 *
 */

SECStatus
NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest,
                       SECItem *contentType)
{
    CERTCertificate *cert;
    SECKEYPrivateKey *privkey = NULL;
    SECOidTag digestalgtag;
    SECOidTag pubkAlgTag;
    SECOidTag signAlgTag;
    SECOidTag cmsSignAlgTag;
    SECItem signature = { 0 };
    SECStatus rv;
    PLArenaPool *poolp, *tmppoolp = NULL;
    SECAlgorithmID *algID, freeAlgID;
    CERTSubjectPublicKeyInfo *spki;

    PORT_Assert(digest != NULL);

    poolp = signerinfo->cmsg->poolp;

    switch (signerinfo->signerIdentifier.identifierType) {
        case NSSCMSSignerID_IssuerSN:
            cert = signerinfo->cert;

            privkey = PK11_FindKeyByAnyCert(cert, signerinfo->cmsg->pwfn_arg);
            if (privkey == NULL)
                goto loser;
            algID = &cert->subjectPublicKeyInfo.algorithm;
            break;
        case NSSCMSSignerID_SubjectKeyID:
            privkey = signerinfo->signingKey;
            signerinfo->signingKey = NULL;
            spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey);
            SECKEY_DestroyPublicKey(signerinfo->pubKey);
            signerinfo->pubKey = NULL;
            SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm);
            SECKEY_DestroySubjectPublicKeyInfo(spki);
            algID = &freeAlgID;
            break;
        default:
            goto loser;
    }
    digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
    /*
     * XXX I think there should be a cert-level interface for this,
     * so that I do not have to know about subjectPublicKeyInfo...
     */

    pubkAlgTag = SECOID_GetAlgorithmTag(algID);
    if (algID == &freeAlgID) {
        SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE);
    }

    signAlgTag = SEC_GetSignatureAlgorithmOidTag(SECKEY_GetPrivateKeyType(privkey),
                                                 digestalgtag);
    if (signAlgTag == SEC_OID_UNKNOWN) {
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
        goto loser;
    }

    cmsSignAlgTag = NSS_CMSSignerInfo_GetSignatureAlgorithmOidTag(
        SECKEY_GetPrivateKeyType(privkey), pubkAlgTag, signAlgTag);
    if (cmsSignAlgTag == SEC_OID_UNKNOWN) {
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
        goto loser;
    }

    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg),
                              cmsSignAlgTag, NULL) != SECSuccess)
        goto loser;

    if (!NSS_SMIMEUtil_SigningAllowed(&signerinfo->digestEncAlg)) {
        PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM);
        goto loser;
    }

    if (signerinfo->authAttr != NULL) {
        SECItem encoded_attrs;

        /* find and fill in the message digest attribute. */
        rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr),
                                           SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE);
        if (rv != SECSuccess)
            goto loser;

        if (contentType != NULL) {
            /* if the caller wants us to, find and fill in the content type attribute. */
            rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr),
                                               SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE);
            if (rv != SECSuccess)
                goto loser;
        }

        if ((tmppoolp = PORT_NewArena(1024)) == NULL) {
            PORT_SetError(SEC_ERROR_NO_MEMORY);
            goto loser;
        }

        /*
         * Before encoding, reorder the attributes so that when they
         * are encoded, they will be conforming DER, which is required
         * to have a specific order and that is what must be used for
         * the hash/signature.  We do this here, rather than building
         * it into EncodeAttributes, because we do not want to do
         * such reordering on incoming messages (which also uses
         * EncodeAttributes) or our old signatures (and other "broken"
         * implementations) will not verify.  So, we want to guarantee
         * that we send out good DER encodings of attributes, but not
         * to expect to receive them.
         */

        if (NSS_CMSAttributeArray_Reorder(signerinfo->authAttr) != SECSuccess)
            goto loser;

        encoded_attrs.data = NULL;
        encoded_attrs.len = 0;
        if (NSS_CMSAttributeArray_Encode(tmppoolp, &(signerinfo->authAttr),
                                         &encoded_attrs) == NULL)
            goto loser;

        rv = SEC_SignData(&signature, encoded_attrs.data, encoded_attrs.len,
                          privkey, signAlgTag);
        PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */
        tmppoolp = 0;
    } else {
        rv = SGN_Digest(privkey, digestalgtag, &signature, digest);
    }
    SECKEY_DestroyPrivateKey(privkey);
    privkey = NULL;

    if (rv != SECSuccess)
        goto loser;

    if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) != SECSuccess)
        goto loser;

    SECITEM_FreeItem(&signature, PR_FALSE);

    return SECSuccess;

loser:
    if (signature.len != 0)
        SECITEM_FreeItem(&signature, PR_FALSE);
    if (privkey)
        SECKEY_DestroyPrivateKey(privkey);
    if (tmppoolp)
        PORT_FreeArena(tmppoolp, PR_FALSE);
    return SECFailure;
}

SECStatus
NSS_CMSSignerInfo_VerifyCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb,
                                    SECCertUsage certusage)
{
    CERTCertificate *cert;
    PRTime stime;

    if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb)) == NULL) {
        signerinfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
        return SECFailure;
    }

    /*
     * Get and convert the signing time; if available, it will be used
     * both on the cert verification and for importing the sender
     * email profile.
     */

    if (NSS_CMSSignerInfo_GetSigningTime(signerinfo, &stime) != SECSuccess)
        stime = PR_Now(); /* not found or conversion failed, so check against now */

    /*
     * XXX  This uses the signing time, if available.  Additionally, we
     * might want to, if there is no signing time, get the message time
     * from the mail header itself, and use that.  That would require
     * a change to our interface though, and for S/MIME callers to pass
     * in a time (and for non-S/MIME callers to pass in nothing, or
     * maybe make them pass in the current time, always?).
     */

    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certusage, stime,
                        signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
        signerinfo->verificationStatus = NSSCMSVS_SigningCertNotTrusted;
        return SECFailure;
    }
    return SECSuccess;
}

/*
 * NSS_CMSSignerInfo_Verify - verify the signature of a single SignerInfo
 *
 * Just verifies the signature. The assumption is that verification of
 * the certificate is done already.
 */

SECStatus
NSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo,
                         SECItem *digest,      /* may be NULL */
                         SECItem *contentType) /* may be NULL */
{
    SECKEYPublicKey *publickey = NULL;
    NSSCMSAttribute *attr;
    SECItem encoded_attrs;
    CERTCertificate *cert;
    NSSCMSVerificationStatus vs = NSSCMSVS_Unverified;
    PLArenaPool *poolp;
    SECOidTag digestalgtag;
    SECOidTag pubkAlgTag;
    SECOidTag digestalgtagCmp;
    SECOidTag sigAlgTag;

    if (signerinfo == NULL)
        return SECFailure;

    /* NSS_CMSSignerInfo_GetSigningCertificate will fail if 2nd parm is NULL
    ** and cert has not been verified
    */

    cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, NULL);
    if (cert == NULL) {
        vs = NSSCMSVS_SigningCertNotFound;
        goto loser;
    }

    if ((publickey = CERT_ExtractPublicKey(cert)) == NULL) {
        vs = NSSCMSVS_ProcessingError;
        goto loser;
    }

    digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
    pubkAlgTag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
    sigAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg));
    if ((pubkAlgTag == SEC_OID_UNKNOWN) || (digestalgtag == SEC_OID_UNKNOWN) ||
        (sigAlgTag == SEC_OID_UNKNOWN)) {
        vs = NSSCMSVS_SignatureAlgorithmUnknown;
        goto loser;
    }
    if (!NSS_SMIMEUtil_SigningAllowed(&signerinfo->digestEncAlg)) {
        vs = NSSCMSVS_SignatureAlgorithmUnsupported;
        goto loser;
    }

    if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
        if (contentType) {
            /*
             * Check content type
             *
             * RFC2630 sez that if there are any authenticated attributes,
             * then there must be one for content type which matches the
             * content type of the content being signed, and there must
             * be one for message digest which matches our message digest.
             * So check these things first.
             */

            attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
                                                          SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE);
            if (attr == NULL) {
                vs = NSSCMSVS_MalformedSignature;
                goto loser;
            }

            if (NSS_CMSAttribute_CompareValue(attr, contentType) == PR_FALSE) {
                vs = NSSCMSVS_MalformedSignature;
                goto loser;
            }
        }

        /*
         * Check digest
         */

        attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
                                                      SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE);
        if (attr == NULL) {
            vs = NSSCMSVS_MalformedSignature;
            goto loser;
        }
        if (!digest ||
            NSS_CMSAttribute_CompareValue(attr, digest) == PR_FALSE) {
            vs = NSSCMSVS_DigestMismatch;
            goto loser;
        }

        if ((poolp = PORT_NewArena(1024)) == NULL) {
            vs = NSSCMSVS_ProcessingError;
            goto loser;
        }

        /*
         * Check signature
         *
         * The signature is based on a digest of the DER-encoded authenticated
         * attributes.  So, first we encode and then we digest/verify.
         * we trust the decoder to have the attributes in the right (sorted)
         * order
         */

        encoded_attrs.data = NULL;
        encoded_attrs.len = 0;

        if (NSS_CMSAttributeArray_Encode(poolp, &(signerinfo->authAttr),
                                         &encoded_attrs) == NULL ||
            encoded_attrs.data == NULL || encoded_attrs.len == 0) {
            PORT_FreeArena(poolp, PR_FALSE);
            vs = NSSCMSVS_ProcessingError;
            goto loser;
        }

        if (sigAlgTag == pubkAlgTag) {
            /* This is to handle cases in which signatureAlgorithm field
             * specifies the public key algorithm rather than a signature
             * algorithm. */

            vs = (VFY_VerifyDataDirect(encoded_attrs.data, encoded_attrs.len,
                                       publickey, &(signerinfo->encDigest), pubkAlgTag,
                                       digestalgtag, NULL, signerinfo->cmsg->pwfn_arg) != SECSuccess)
                     ? NSSCMSVS_BadSignature
                     : NSSCMSVS_GoodSignature;
        } else {
            if (VFY_VerifyDataWithAlgorithmID(encoded_attrs.data,
                                              encoded_attrs.len, publickey, &(signerinfo->encDigest),
                                              &(signerinfo->digestEncAlg), &digestalgtagCmp,
                                              signerinfo->cmsg->pwfn_arg) != SECSuccess) {
                vs = NSSCMSVS_BadSignature;
            } else if (digestalgtagCmp != digestalgtag) {
                PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
                vs = NSSCMSVS_BadSignature;
            } else {
                vs = NSSCMSVS_GoodSignature;
            }
        }

        PORT_FreeArena(poolp, PR_FALSE); /* awkward memory management :-( */

    } else {
        SECItem *sig;

        /* No authenticated attributes.
         ** The signature is based on the plain message digest.
         */

        sig = &(signerinfo->encDigest);
        if (sig->len == 0)
            goto loser;

        if (sigAlgTag == pubkAlgTag) {
            /* This is to handle cases in which signatureAlgorithm field
             * specifies the public key algorithm rather than a signature
             * algorithm. */

            vs = (!digest ||
                  VFY_VerifyDigestDirect(digest, publickey, sig, pubkAlgTag,
                                         digestalgtag, signerinfo->cmsg->pwfn_arg) != SECSuccess)
                     ? NSSCMSVS_BadSignature
                     : NSSCMSVS_GoodSignature;
        } else {
            vs = (!digest ||
                  VFY_VerifyDigestWithAlgorithmID(digest, publickey, sig,
                                                  &(signerinfo->digestEncAlg), digestalgtag,
                                                  signerinfo->cmsg->pwfn_arg) != SECSuccess)
                     ? NSSCMSVS_BadSignature
                     : NSSCMSVS_GoodSignature;
        }
    }

    if (vs == NSSCMSVS_BadSignature) {
        int error = PORT_GetError();
        /*
         * XXX Change the generic error into our specific one, because
         * in that case we get a better explanation out of the Security
         * Advisor.  This is really a bug in the PSM error strings (the
         * "generic" error has a lousy/wrong message associated with it
         * which assumes the signature verification was done for the
         * purposes of checking the issuer signature on a certificate)
         * but this is at least an easy workaround and/or in the
         * Security Advisor, which specifically checks for the error
         * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
         * in that case but does not similarly check for
         * SEC_ERROR_BAD_SIGNATURE.  It probably should, but then would
         * probably say the wrong thing in the case that it *was* the
         * certificate signature check that failed during the cert
         * verification done above.  Our error handling is really a mess.
         */

        if (error == SEC_ERROR_BAD_SIGNATURE)
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
        /*
         * map algorithm failures to NSSCMSVS values
         */

        if ((error == SEC_ERROR_PKCS7_KEYALG_MISMATCH) ||
            (error == SEC_ERROR_INVALID_ALGORITHM)) {
            /* keep the same error code as 3.11 and before */
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
            vs = NSSCMSVS_SignatureAlgorithmUnsupported;
        }
    }

    if (publickey != NULL)
        SECKEY_DestroyPublicKey(publickey);

    signerinfo->verificationStatus = vs;

    return (vs == NSSCMSVS_GoodSignature) ? SECSuccess : SECFailure;

loser:
    if (publickey != NULL)
        SECKEY_DestroyPublicKey(publickey);

    signerinfo->verificationStatus = vs;

    PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
    return SECFailure;
}

NSSCMSVerificationStatus
NSS_CMSSignerInfo_GetVerificationStatus(NSSCMSSignerInfo *signerinfo)
{
    return signerinfo->verificationStatus;
}

SECOidData *
NSS_CMSSignerInfo_GetDigestAlg(NSSCMSSignerInfo *signerinfo)
{
    SECOidData *algdata;
    SECOidTag algtag;

    algdata = SECOID_FindOID(&(signerinfo->digestAlg.algorithm));
    if (algdata == NULL) {
        return algdata;
    }
    /* Windows may have given us a signer algorithm oid instead of a digest
     * algorithm oid. This call will map to a signer oid to a digest one,
     * otherwise it leaves the oid alone and let the chips fall as they may
     * if it's not a digest oid.
     */

    algtag = NSS_CMSUtil_MapSignAlgs(algdata->offset);
    if (algtag != algdata->offset) {
        /* if the tags don't match, then we must have received a signer
         * algorithID. Now we need to get the oid data for the digest
         * oid, which the rest of the code is expecting */

        algdata = SECOID_FindOIDByTag(algtag);
    }

    return algdata;
}

SECOidTag
NSS_CMSSignerInfo_GetDigestAlgTag(NSSCMSSignerInfo *signerinfo)
{
    SECOidData *algdata;

    if (!signerinfo) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SEC_OID_UNKNOWN;
    }

    algdata = NSS_CMSSignerInfo_GetDigestAlg(signerinfo);
    if (algdata != NULL)
        return algdata->offset;
    else
        return SEC_OID_UNKNOWN;
}

CERTCertificateList *
NSS_CMSSignerInfo_GetCertList(NSSCMSSignerInfo *signerinfo)
{
    return signerinfo->certList;
}

int
NSS_CMSSignerInfo_GetVersion(NSSCMSSignerInfo *signerinfo)
{
    unsigned long version;

    /* always take apart the SECItem */
    if (SEC_ASN1DecodeInteger(&(signerinfo->version), &version) != SECSuccess)
        return 0;
    else
        return (int)version;
}

/*
 * NSS_CMSSignerInfo_GetSigningTime - return the signing time,
 *                    in UTCTime or GeneralizedTime format,
 *                                    of a CMS signerInfo.
 *
 * sinfo - signerInfo data for this signer
 *
 * Returns a pointer to XXXX (what?)
 * A return value of NULL is an error.
 */

SECStatus
NSS_CMSSignerInfo_GetSigningTime(NSSCMSSignerInfo *sinfo, PRTime *stime)
{
    NSSCMSAttribute *attr;
    SECItem *value;

    if (sinfo == NULL)
        return SECFailure;

    if (sinfo->signingTime != 0) {
        *stime = sinfo->signingTime; /* cached copy */
        return SECSuccess;
    }

    attr = NSS_CMSAttributeArray_FindAttrByOidTag(sinfo->authAttr,
                                                  SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
    /* XXXX multi-valued attributes NIH */
    if (attr == NULL || (value = NSS_CMSAttribute_GetValue(attr)) == NULL)
        return SECFailure;
    if (DER_DecodeTimeChoice(stime, value) != SECSuccess)
        return SECFailure;
    sinfo->signingTime = *stime; /* make cached copy */
    return SECSuccess;
}

/*
 * Return the signing cert of a CMS signerInfo.
 *
 * the certs in the enclosing SignedData must have been imported already
 */

CERTCertificate *
NSS_CMSSignerInfo_GetSigningCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb)
{
    CERTCertificate *cert;
    NSSCMSSignerIdentifier *sid;

    if (signerinfo->cert != NULL)
        return signerinfo->cert;

    /* no certdb, and cert hasn't been set yet? */
    if (certdb == NULL)
        return NULL;

    /*
     * This cert will also need to be freed, but since we save it
     * in signerinfo for later, we do not want to destroy it when
     * we leave this function -- we let the clean-up of the entire
     * cinfo structure later do the destroy of this cert.
     */

    sid = &signerinfo->signerIdentifier;
    switch (sid->identifierType) {
        case NSSCMSSignerID_IssuerSN:
            cert = CERT_FindCertByIssuerAndSN(certdb, sid->id.issuerAndSN);
            break;
        case NSSCMSSignerID_SubjectKeyID:
            cert = CERT_FindCertBySubjectKeyID(certdb, sid->id.subjectKeyID);
            break;
        default:
            cert = NULL;
            break;
    }

    /* cert can be NULL at that point */
    signerinfo->cert = cert; /* earmark it */

    return cert;
}

/*
 * NSS_CMSSignerInfo_GetSignerCommonName - return the common name of the signer
 *
 * sinfo - signerInfo data for this signer
 *
 * Returns a pointer to allocated memory, which must be freed with PORT_Free.
 * A return value of NULL is an error.
 */

char *
NSS_CMSSignerInfo_GetSignerCommonName(NSSCMSSignerInfo *sinfo)
{
    CERTCertificate *signercert;

    /* will fail if cert is not verified */
    if ((signercert = NSS_CMSSignerInfo_GetSigningCertificate(sinfo, NULL)) == NULL)
        return NULL;

    return (CERT_GetCommonName(&signercert->subject));
}

/*
 * NSS_CMSSignerInfo_GetSignerEmailAddress - return the common name of the signer
 *
 * sinfo - signerInfo data for this signer
 *
 * Returns a pointer to allocated memory, which must be freed.
 * A return value of NULL is an error.
 */

char *
NSS_CMSSignerInfo_GetSignerEmailAddress(NSSCMSSignerInfo *sinfo)
{
    CERTCertificate *signercert;

    if ((signercert = NSS_CMSSignerInfo_GetSigningCertificate(sinfo, NULL)) == NULL)
        return NULL;

    if (!signercert->emailAddr || !signercert->emailAddr[0])
        return NULL;

    return (PORT_Strdup(signercert->emailAddr));
}

/*
 * NSS_CMSSignerInfo_AddAuthAttr - add an attribute to the
 * authenticated (i.e. signed) attributes of "signerinfo".
 */

SECStatus
NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
{
    return NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr);
}

/*
 * NSS_CMSSignerInfo_AddUnauthAttr - add an attribute to the
 * unauthenticated attributes of "signerinfo".
 */

SECStatus
NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
{
    return NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
}

/*
 * NSS_CMSSignerInfo_AddSigningTime - add the signing time to the
 * authenticated (i.e. signed) attributes of "signerinfo".
 *
 * 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 do nothing.
 *
 * XXX This will probably just shove the current time into "signerinfo"
 * but it will not actually get signed until the entire item is
 * processed for encoding.  Is this (expected to be small) delay okay?
 */

SECStatus
NSS_CMSSignerInfo_AddSigningTime(NSSCMSSignerInfo *signerinfo, PRTime t)
{
    NSSCMSAttribute *attr;
    SECItem stime;
    void *mark;
    PLArenaPool *poolp;

    poolp = signerinfo->cmsg->poolp;

    mark = PORT_ArenaMark(poolp);

    /* create new signing time attribute */
    if (DER_EncodeTimeChoice(NULL, &stime, t) != SECSuccess)
        goto loser;

    if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_PKCS9_SIGNING_TIME, &stime, PR_FALSE)) == NULL) {
        SECITEM_FreeItem(&stime, PR_FALSE);
        goto loser;
    }

    SECITEM_FreeItem(&stime, PR_FALSE);

    if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
        goto loser;

    PORT_ArenaUnmark(poolp, mark);

    return SECSuccess;

loser:
    PORT_ArenaRelease(poolp, mark);
    return SECFailure;
}

/*
 * NSS_CMSSignerInfo_AddSMIMECaps - add a SMIMECapabilities attribute to the
 * authenticated (i.e. signed) attributes of "signerinfo".
 *
 * This is expected to be included in outgoing signed
 * messages for email (S/MIME).
 */

SECStatus
NSS_CMSSignerInfo_AddSMIMECaps(NSSCMSSignerInfo *signerinfo)
{
    NSSCMSAttribute *attr;
    SECItem *smimecaps = NULL;
    void *mark;
    PLArenaPool *poolp;

    poolp = signerinfo->cmsg->poolp;

    mark = PORT_ArenaMark(poolp);

    smimecaps = SECITEM_AllocItem(poolp, NULL, 0);
    if (smimecaps == NULL)
        goto loser;

    /* create new signing time attribute */
    if (NSS_SMIMEUtil_CreateSMIMECapabilities(poolp, smimecaps) != SECSuccess)
        goto loser;

    if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_PKCS9_SMIME_CAPABILITIES, smimecaps, PR_TRUE)) == NULL)
        goto loser;

    if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
        goto loser;

    PORT_ArenaUnmark(poolp, mark);
    return SECSuccess;

loser:
    PORT_ArenaRelease(poolp, mark);
    return SECFailure;
}

/*
 * NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
 * authenticated (i.e. signed) attributes of "signerinfo".
 *
 * This is expected to be included in outgoing signed messages for email (S/MIME).
 */

SECStatus
NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb)
{
    NSSCMSAttribute *attr;
    SECItem *smimeekp = NULL;
    void *mark;
    PLArenaPool *poolp;

    /* verify this cert for encryption */
    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
        return SECFailure;
    }

    poolp = signerinfo->cmsg->poolp;
    mark = PORT_ArenaMark(poolp);

    smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
    if (smimeekp == NULL)
        goto loser;

    /* create new signing time attribute */
    if (NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
        goto loser;

    if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
        goto loser;

    if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
        goto loser;

    PORT_ArenaUnmark(poolp, mark);
    return SECSuccess;

loser:
    PORT_ArenaRelease(poolp, mark);
    return SECFailure;
}

/*
 * NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
 * authenticated (i.e. signed) attributes of "signerinfo", using the OID preferred by Microsoft.
 *
 * This is expected to be included in outgoing signed messages for email (S/MIME),
 * if compatibility with Microsoft mail clients is wanted.
 */

SECStatus
NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb)
{
    NSSCMSAttribute *attr;
    SECItem *smimeekp = NULL;
    void *mark;
    PLArenaPool *poolp;

    /* verify this cert for encryption */
    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
        return SECFailure;
    }

    poolp = signerinfo->cmsg->poolp;
    mark = PORT_ArenaMark(poolp);

    smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
    if (smimeekp == NULL)
        goto loser;

    /* create new signing time attribute */
    if (NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
        goto loser;

    if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
        goto loser;

    if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
        goto loser;

    PORT_ArenaUnmark(poolp, mark);
    return SECSuccess;

loser:
    PORT_ArenaRelease(poolp, mark);
    return SECFailure;
}

/*
 * NSS_CMSSignerInfo_AddCounterSignature - countersign a signerinfo
 *
 * 1. digest the DER-encoded signature value of the original signerinfo
 * 2. create new signerinfo with correct version, sid, digestAlg
 * 3. add message-digest authAttr, but NO content-type
 * 4. sign the authAttrs
 * 5. DER-encode the new signerInfo
 * 6. add the whole thing to original signerInfo's unAuthAttrs
 *    as a SEC_OID_PKCS9_COUNTER_SIGNATURE attribute
 *
 * XXXX give back the new signerinfo?
 */

SECStatus
NSS_CMSSignerInfo_AddCounterSignature(NSSCMSSignerInfo *signerinfo,
                                      SECOidTag digestalg, CERTCertificate signingcert)
{
    /* XXXX TBD XXXX */
    return SECFailure;
}

/*
 * XXXX the following needs to be done in the S/MIME layer code
 * after signature of a signerinfo is verified
 */

SECStatus
NSS_SMIMESignerInfo_SaveSMIMEProfile(NSSCMSSignerInfo *signerinfo)
{
    CERTCertificate *cert = NULL;
    SECItem *profile = NULL;
    NSSCMSAttribute *attr;
    SECItem *stime = NULL;
    SECItem *ekp;
    CERTCertDBHandle *certdb;
    int save_error;
    SECStatus rv;
    PRBool must_free_cert = PR_FALSE;

    certdb = CERT_GetDefaultCertDB();

    /* sanity check - see if verification status is ok (unverified does not count...) */
    if (signerinfo->verificationStatus != NSSCMSVS_GoodSignature)
        return SECFailure;

    /* find preferred encryption cert */
    if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr) &&
        (attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
                                                       SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL) { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! */
        ekp = NSS_CMSAttribute_GetValue(attr);
        if (ekp == NULL)
            return SECFailure;

        /* we assume that all certs coming with the message have been imported to the */
        /* temporary database */
        cert = NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(certdb, ekp);
        if (cert == NULL)
            return SECFailure;
        must_free_cert = PR_TRUE;
    }

    if (cert == NULL) {
        /* no preferred cert found?
         * find the cert the signerinfo is signed with instead */

        cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb);
        if (cert == NULL || cert->emailAddr == NULL || !cert->emailAddr[0])
            return SECFailure;
    }

/* verify this cert for encryption (has been verified for signing so far) */
/* don't verify this cert for encryption. It may just be a signing cert.
 * that's OK, we can still save the S/MIME profile. The encryption cert
 * should have already been saved */

#ifdef notdef
    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
        if (must_free_cert)
            CERT_DestroyCertificate(cert);
        return SECFailure;
    }
#endif

    /* XXX store encryption cert permanently? */

    /*
     * Remember the current error set because we do not care about
     * anything set by the functions we are about to call.
     */

    save_error = PORT_GetError();

    if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
        attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
                                                      SEC_OID_PKCS9_SMIME_CAPABILITIES,
                                                      PR_TRUE);
        profile = NSS_CMSAttribute_GetValue(attr);
        attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
                                                      SEC_OID_PKCS9_SIGNING_TIME,
                                                      PR_TRUE);
        stime = NSS_CMSAttribute_GetValue(attr);
    }

    rv = CERT_SaveSMimeProfile(cert, profile, stime);
    if (must_free_cert)
        CERT_DestroyCertificate(cert);

    /*
     * Restore the saved error in case the calls above set a new
     * one that we do not actually care about.
     */

    PORT_SetError(save_error);

    return rv;
}

/*
 * NSS_CMSSignerInfo_IncludeCerts - set cert chain inclusion mode for this signer
 */

SECStatus
NSS_CMSSignerInfo_IncludeCerts(NSSCMSSignerInfo *signerinfo,
                               NSSCMSCertChainMode cm, SECCertUsage usage)
{
    if (signerinfo->cert == NULL)
        return SECFailure;

    /* don't leak if we get called twice */
    if (signerinfo->certList != NULL) {
        CERT_DestroyCertificateList(signerinfo->certList);
        signerinfo->certList = NULL;
    }

    switch (cm) {
        case NSSCMSCM_None:
            signerinfo->certList = NULL;
            break;
        case NSSCMSCM_CertOnly:
            signerinfo->certList = CERT_CertListFromCert(signerinfo->cert);
            break;
        case NSSCMSCM_CertChain:
            signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert,
                                                          usage, PR_FALSE);
            break;
        case NSSCMSCM_CertChainWithRoot:
            signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert,
                                                          usage, PR_TRUE);
            break;
    }

    if (cm != NSSCMSCM_None && signerinfo->certList == NULL)
        return SECFailure;

    return SECSuccess;
}

Messung V0.5
C=91 H=89 G=89

¤ Dauer der Verarbeitung: 0.10 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.