Пример #1
0
/*
 * NSS_CMSEncryptedData_Encode_BeforeStart - do all the necessary things to a EncryptedData
 *     before encoding begins.
 *
 * In particular:
 *  - set the correct version value.
 *  - get the encryption key
 */
SECStatus
NSS_CMSEncryptedData_Encode_BeforeStart(NSSCMSEncryptedData *encd)
{
    int version;
    PK11SymKey *bulkkey = NULL;
    SECItem *dummy;
    NSSCMSContentInfo *cinfo = &(encd->contentInfo);

    if (NSS_CMSArray_IsEmpty((void **)encd->unprotectedAttr))
	version = NSS_CMS_ENCRYPTED_DATA_VERSION;
    else
	version = NSS_CMS_ENCRYPTED_DATA_VERSION_UPATTR;
    
    dummy = SEC_ASN1EncodeInteger (encd->cmsg->poolp, &(encd->version), version);
    if (dummy == NULL)
	return SECFailure;

    /* now get content encryption key (bulk key) by using our cmsg callback */
    if (encd->cmsg->decrypt_key_cb)
	bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, 
		    NSS_CMSContentInfo_GetContentEncAlg(cinfo));
    if (bulkkey == NULL)
	return SECFailure;

    /* store the bulk key in the contentInfo so that the encoder can find it */
    NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
    PK11_FreeSymKey (bulkkey);

    return SECSuccess;
}
/*
 * NSS_CMSMessage_IsSigned - see if message contains a signed submessage
 *
 * If the CMS message has a SignedData with a signature (not just a SignedData)
 * 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.
 */
PRBool
NSS_CMSMessage_IsSigned(NSSCMSMessage *cmsg)
{
    NSSCMSContentInfo *cinfo;

    /* walk down the chain of contentinfos */
    for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo))
    {
	switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
	case SEC_OID_PKCS7_SIGNED_DATA:
	    if (!NSS_CMSArray_IsEmpty((void **)cinfo->content.signedData->signerInfos))
		return PR_TRUE;
	    break;
	default:
	    /* callback here for generic wrappers? */
	    break;
	}
    }
    return PR_FALSE;
}
Пример #3
0
/*
 * 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;
}
Пример #4
0
/*
 * 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;

    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(&(signerinfo->digestEncAlg));
    if ((pubkAlgTag == SEC_OID_UNKNOWN) || (digestalgtag == SEC_OID_UNKNOWN)) {
	vs = NSSCMSVS_SignatureAlgorithmUnknown;
	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;
	}

	vs = (VFY_VerifyDataDirect(encoded_attrs.data, encoded_attrs.len,
		publickey, &(signerinfo->encDigest), pubkAlgTag,
		digestalgtag, NULL, signerinfo->cmsg->pwfn_arg) != SECSuccess) 
		? NSSCMSVS_BadSignature : 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;

	vs = (!digest || 
	      VFY_VerifyDigestDirect(digest, publickey, sig, pubkAlgTag,
		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;
}