int oauth_verify_rsa_sha1 (const char *m, const char *c, const char *sig) { PK11SlotInfo *slot = NULL; SECKEYPublicKey *pkey = NULL; CERTCertificate *cert = NULL; SECItem signature; SECStatus s; SECItem der; int rv=0; char *key = oauth_strip_pkcs(c, NS_CERT_HEADER, NS_CERT_TRAILER); if (!key) return 0; oauth_init_nss(); s = ATOB_ConvertAsciiToItem(&signature, (char*) sig); // XXX cast (const char*) -> (char*) if (s != SECSuccess) goto looser; slot = PK11_GetInternalKeySlot(); if (!slot) goto looser; s = ATOB_ConvertAsciiToItem(&der, key); if (s != SECSuccess) goto looser; cert = __CERT_DecodeDERCertificate(&der, PR_TRUE, NULL); SECITEM_FreeItem(&der, PR_FALSE); if (!cert) goto looser; pkey = CERT_ExtractPublicKey(cert); if (!pkey) goto looser; if (pkey->keyType != rsaKey) goto looser; s = VFY_VerifyData((unsigned char*) m, strlen(m), pkey, &signature, SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, NULL); if (s == SECSuccess) rv=1; #if 0 else if (PR_GetError()!= SEC_ERROR_BAD_SIGNATURE) rv=-1; #endif looser: if (pkey) SECKEY_DestroyPublicKey(pkey); if (slot) PK11_FreeSlot(slot); free(key); return rv; }
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; }