コード例 #1
0
/*
 * SecCmsAttributeArrayAddAttr - add an attribute to an
 * array of attributes. 
 */
OSStatus
SecCmsAttributeArrayAddAttr(PLArenaPool *poolp, SecCmsAttribute ***attrs, SecCmsAttribute *attr)
{
    SecCmsAttribute *oattr;
    void *mark;
    SECOidTag type;

    mark = PORT_ArenaMark(poolp);

    /* find oidtag of attr */
    type = SecCmsAttributeGetType(attr);

    /* see if we have one already */
    oattr = SecCmsAttributeArrayFindAttrByOidTag(*attrs, type, PR_FALSE);
    PORT_Assert (oattr == NULL);
    if (oattr != NULL)
	goto loser;	/* XXX or would it be better to replace it? */

    /* no, shove it in */
    if (SecCmsArrayAdd(poolp, (void ***)attrs, (void *)attr) != SECSuccess)
	goto loser;

    PORT_ArenaUnmark(poolp, mark);
    return SECSuccess;

loser:
    PORT_ArenaRelease(poolp, mark);
    return SECFailure;
}
コード例 #2
0
/*
 * SecCmsAttributeArraySetAttr - set an attribute's value in a set of attributes
 */
OSStatus
SecCmsAttributeArraySetAttr(PLArenaPool *poolp, SecCmsAttribute ***attrs, SECOidTag type, CSSM_DATA_PTR value, Boolean encoded)
{
    SecCmsAttribute *attr;
    void *mark;

    mark = PORT_ArenaMark(poolp);

    /* see if we have one already */
    attr = SecCmsAttributeArrayFindAttrByOidTag(*attrs, type, PR_FALSE);
    if (attr == NULL) {
	/* not found? create one! */
	attr = SecCmsAttributeCreate(poolp, type, value, encoded);
	if (attr == NULL)
	    goto loser;
	/* and add it to the list */
	if (SecCmsArrayAdd(poolp, (void ***)attrs, (void *)attr) != SECSuccess)
	    goto loser;
    } else {
	/* found, shove it in */
	/* XXX we need a decent memory model @#$#$!#!!! */
	attr->values[0] = value;
	attr->encoded = encoded;
    }

    PORT_ArenaUnmark (poolp, mark);
    return SECSuccess;

loser:
    PORT_ArenaRelease (poolp, mark);
    return SECFailure;
}
コード例 #3
0
/*!
     @function
     @abstract Return the data in the signed Codesigning Hash Agility attribute.
     @param sinfo SignerInfo data for this signer, pointer to a CFDataRef for attribute value
     @discussion Returns a CFDataRef containing the value of the attribute
     @result A return value of errSecInternal is an error trying to look up the oid.
             A status value of success with null result data indicates the attribute was not present.
 */
OSStatus
SecCmsSignerInfoGetAppleCodesigningHashAgility(SecCmsSignerInfoRef sinfo, CFDataRef *sdata)
{
    SecCmsAttribute *attr;
    CSSM_DATA_PTR value;

    if (sinfo == NULL || sdata == NULL)
        return paramErr;

    *sdata = NULL;

    if (sinfo->hashAgilityAttrValue != NULL) {
        *sdata = sinfo->hashAgilityAttrValue;	/* cached copy */
        return SECSuccess;
    }

    attr = SecCmsAttributeArrayFindAttrByOidTag(sinfo->authAttr, SEC_OID_APPLE_HASH_AGILITY, PR_TRUE);

    /* attribute not found */
    if (attr == NULL || (value = SecCmsAttributeGetValue(attr)) == NULL)
        return SECSuccess;

    sinfo->hashAgilityAttrValue = CFDataCreate(NULL, value->Data, value->Length);	/* make cached copy */
    if (sinfo->hashAgilityAttrValue) {
        *sdata = sinfo->hashAgilityAttrValue;
        return SECSuccess;
    }
    return errSecAllocate;
}
コード例 #4
0
OSStatus
SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeStampPolicy)
{
    /*
        unAuthAttr is an array of attributes; we expect to
        see just one: the timestamp blob. If we have an unAuthAttr,
        but don't see a timestamp, return an error since we have
        no other cases where this would be present.
    */

    SecCmsAttribute *attr = NULL;    
    OSStatus status = SECFailure;
    
    require(signerinfo, xit);
    attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->unAuthAttr,
        SEC_OID_PKCS9_TIMESTAMP_TOKEN, PR_TRUE);
    if (attr == NULL)
    {
        status = errSecTimestampMissing;
        goto xit;
    }

    dprintf("found an id-ct-TSTInfo\n");
    // Don't check the nonce in this case
    status = decodeTimeStampTokenWithPolicy(signerinfo, timeStampPolicy, (attr->values)[0], &signerinfo->encDigest, 0);
xit:
    return status;
}
コード例 #5
0
/*
 * SecCmsSignerInfoGetSigningTime - return the signing time,
 *				      in UTCTime 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.
 */
OSStatus
SecCmsSignerInfoGetSigningTime(SecCmsSignerInfoRef sinfo, CFAbsoluteTime *stime)
{
    SecCmsAttribute *attr;
    CSSM_DATA_PTR value;

    if (sinfo == NULL)
	return paramErr;

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

    attr = SecCmsAttributeArrayFindAttrByOidTag(sinfo->authAttr, SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
    /* XXXX multi-valued attributes NIH */
    if (attr == NULL || (value = SecCmsAttributeGetValue(attr)) == NULL)
	return errSecSigningTimeMissing;
    if (DER_UTCTimeToCFDate(value, stime) != SECSuccess)
	return errSecSigningTimeMissing;
    sinfo->signingTime = *stime;	/* make cached copy */
    return SECSuccess;
}
コード例 #6
0
OSStatus
SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeStampPolicy, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType)
{
    SecPublicKeyRef publickey = NULL;
    SecCmsAttribute *attr;
    CSSM_DATA encoded_attrs;
    SecCertificateRef cert;
    SecCmsVerificationStatus vs = SecCmsVSUnverified;
    PLArenaPool *poolp;
    SECOidTag digestAlgTag, digestEncAlgTag;
    
    if (signerinfo == NULL)
	return SECFailure;
    
    /* SecCmsSignerInfoGetSigningCertificate will fail if 2nd parm is NULL and */
    /* cert has not been verified */
    if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, NULL)) == NULL) {
	dprintf("SecCmsSignerInfoVerify: no signing cert\n");
	vs = SecCmsVSSigningCertNotFound;
	goto loser;
    }

    dprintfRC("SecCmsSignerInfoVerify top: cert %p cert.rc %d\n", cert, (int)CFGetRetainCount(cert));
    
    debugShowSigningCertificate(signerinfo);

    OSStatus status;
    if ((status = SecCertificateCopyPublicKey(cert, &publickey))) {
        syslog(LOG_ERR, "SecCmsSignerInfoVerifyWithPolicy: copy public key failed %d", (int)status);
	vs = SecCmsVSProcessingError;
	goto loser;
    }

    digestAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestAlg));
    digestEncAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg));
    
    /*
     * Gross hack necessitated by RFC 3278 section 2.1.1, which states 
     * that the signature algorithm (here, digestEncAlg) contains ecdsa_with-SHA1, 
     * *not* (as in all other algorithms) the raw signature algorithm, e.g. 
     * pkcs1RSAEncryption.
     */
    if(digestEncAlgTag == SEC_OID_ECDSA_WithSHA1) {
	digestEncAlgTag = SEC_OID_EC_PUBLIC_KEY;
    }
    
    if (!SecCmsArrayIsEmpty((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.
	     */
	    if ((attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
					SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE)) == NULL)
	    {
		vs = SecCmsVSMalformedSignature;
		goto loser;
	    }
		
	    if (SecCmsAttributeCompareValue(attr, contentType) == PR_FALSE) {
		vs = SecCmsVSMalformedSignature;
		goto loser;
	    }
	}

	/*
	 * Check digest
	 */
	if ((attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE)) == NULL)
	{
	    vs = SecCmsVSMalformedSignature;
	    goto loser;
	}
	if (SecCmsAttributeCompareValue(attr, digest) == PR_FALSE) {
	    vs = SecCmsVSDigestMismatch;
	    goto loser;
	}

	if ((poolp = PORT_NewArena (1024)) == NULL) {
	    vs = SecCmsVSProcessingError;
	    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.Length = 0;

	if (SecCmsAttributeArrayEncode(poolp, &(signerinfo->authAttr), &encoded_attrs) == NULL ||
		encoded_attrs.Data == NULL || encoded_attrs.Length == 0)
	{
	    vs = SecCmsVSProcessingError;
	    goto loser;
	}

	vs = (VFY_VerifyData (encoded_attrs.Data, (int)encoded_attrs.Length,
			publickey, &(signerinfo->encDigest),
			digestAlgTag, digestEncAlgTag,
			signerinfo->cmsg->pwfn_arg) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature;

        dprintf("VFY_VerifyData (authenticated attributes): %s\n",
            (vs == SecCmsVSGoodSignature)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature");

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

    } else {
	CSSM_DATA_PTR sig;

	/* No authenticated attributes. The signature is based on the plain message digest. */
	sig = &(signerinfo->encDigest);
	if (sig->Length == 0)
	    goto loser;

	vs = (VFY_VerifyDigest(digest, publickey, sig,
			digestAlgTag, digestEncAlgTag,
			signerinfo->cmsg->pwfn_arg) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature;

        dprintf("VFY_VerifyData (plain message digest): %s\n",
            (vs == SecCmsVSGoodSignature)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature");
    }
    
    if (!SecCmsArrayIsEmpty((void **)signerinfo->unAuthAttr))
    {
        dprintf("found an unAuthAttr\n");
        OSStatus rux = SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(signerinfo,timeStampPolicy);
        dprintf("SecCmsSignerInfoVerifyUnAuthAttrs Status: %ld\n", (long)rux);
        if (rux) {
            goto loser;
        }
    }

    if (vs == SecCmsVSBadSignature) {
	/*
	 * 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 our 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 (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE)
	    PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
    }

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

    signerinfo->verificationStatus = vs;
    dprintfRC("SecCmsSignerInfoVerify end: cerp %p cert.rc %d\n",
	    cert, (int)CFGetRetainCount(cert));

    dprintf("verificationStatus: %d\n", vs);

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

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

    dprintf("verificationStatus2: %d\n", vs);
    signerinfo->verificationStatus = vs;

    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
    return SECFailure;
}
コード例 #7
0
/*
 * XXXX the following needs to be done in the S/MIME layer code
 * after signature of a signerinfo is verified
 */
OSStatus
SecCmsSignerInfoSaveSMIMEProfile(SecCmsSignerInfoRef signerinfo)
{
    SecCertificateRef cert = NULL;
    CSSM_DATA_PTR profile = NULL;
    SecCmsAttribute *attr;
    CSSM_DATA_PTR utc_stime = NULL;
    CSSM_DATA_PTR ekp;
    int save_error;
    OSStatus rv;
    Boolean must_free_cert = PR_FALSE;
    OSStatus status;
    SecKeychainRef keychainOrArray;
    
    status = SecKeychainCopyDefault(&keychainOrArray);

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

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

	/* we assume that all certs coming with the message have been imported to the */
	/* temporary database */
	cert = SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray, 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 */
	CFStringRef emailAddress=NULL;

	cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, keychainOrArray);
	if (cert == NULL)
	    return SECFailure;
	if (SecCertificateGetEmailAddress(cert,&emailAddress))
	    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(keychainOrArray, cert, certUsageEmailRecipient, CFAbsoluteTimeGetCurrent(), 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 (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr)) {
	attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
				       SEC_OID_PKCS9_SMIME_CAPABILITIES,
				       PR_TRUE);
	profile = SecCmsAttributeGetValue(attr);
	attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
				       SEC_OID_PKCS9_SIGNING_TIME,
				       PR_TRUE);
	utc_stime = SecCmsAttributeGetValue(attr);
    }

    rv = CERT_SaveSMimeProfile (cert, profile, utc_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;
}