/* * 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; }
SECStatus VerifySignedData(const SignedDataWithSignature& sd, const SECItem& subjectPublicKeyInfo, void* pkcs11PinArg) { if (!sd.data.data || !sd.signature.data) { PR_NOT_REACHED("invalid args to VerifySignedData"); PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } // See bug 921585. if (sd.data.len > static_cast<unsigned int>(std::numeric_limits<int>::max())) { PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } SECOidTag pubKeyAlg; SECOidTag digestAlg; switch (sd.algorithm) { case SignatureAlgorithm::ecdsa_with_sha512: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA512; break; case SignatureAlgorithm::ecdsa_with_sha384: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA384; break; case SignatureAlgorithm::ecdsa_with_sha256: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::ecdsa_with_sha1: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA1; break; case SignatureAlgorithm::rsa_pkcs1_with_sha512: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA512; break; case SignatureAlgorithm::rsa_pkcs1_with_sha384: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA384; break; case SignatureAlgorithm::rsa_pkcs1_with_sha256: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::rsa_pkcs1_with_sha1: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA1; break; case SignatureAlgorithm::dsa_with_sha256: pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::dsa_with_sha1: pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; digestAlg = SEC_OID_SHA1; break; default: PR_NOT_REACHED("unknown signature algorithm"); PR_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 0); return SECFailure; } ScopedSECKeyPublicKey pubKey; if (CheckPublicKeySize(subjectPublicKeyInfo, pubKey) != SECSuccess) { return SECFailure; } // The static_cast is safe according to the check above that references // bug 921585. return VFY_VerifyDataDirect(sd.data.data, static_cast<int>(sd.data.len), pubKey.get(), &sd.signature, pubKeyAlg, digestAlg, nullptr, pkcs11PinArg); }
Result VerifySignedData(const SignedDataWithSignature& sd, Input subjectPublicKeyInfo, void* pkcs11PinArg) { // See bug 921585. if (sd.data.GetLength() > static_cast<unsigned int>(std::numeric_limits<int>::max())) { return Result::FATAL_ERROR_INVALID_ARGS; } SECOidTag pubKeyAlg; SECOidTag digestAlg; switch (sd.algorithm) { case SignatureAlgorithm::ecdsa_with_sha512: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA512; break; case SignatureAlgorithm::ecdsa_with_sha384: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA384; break; case SignatureAlgorithm::ecdsa_with_sha256: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::ecdsa_with_sha1: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA1; break; case SignatureAlgorithm::rsa_pkcs1_with_sha512: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA512; break; case SignatureAlgorithm::rsa_pkcs1_with_sha384: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA384; break; case SignatureAlgorithm::rsa_pkcs1_with_sha256: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::rsa_pkcs1_with_sha1: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA1; break; case SignatureAlgorithm::dsa_with_sha256: pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::dsa_with_sha1: pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; digestAlg = SEC_OID_SHA1; break; default: PR_NOT_REACHED("unknown signature algorithm"); return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED; } Result rv; ScopedSECKeyPublicKey pubKey; rv = CheckPublicKeySize(subjectPublicKeyInfo, pubKey); if (rv != Success) { return rv; } // The static_cast is safe according to the check above that references // bug 921585. SECItem dataSECItem(UnsafeMapInputToSECItem(sd.data)); SECItem signatureSECItem(UnsafeMapInputToSECItem(sd.signature)); SECStatus srv = VFY_VerifyDataDirect(dataSECItem.data, static_cast<int>(dataSECItem.len), pubKey.get(), &signatureSECItem, pubKeyAlg, digestAlg, nullptr, pkcs11PinArg); if (srv != SECSuccess) { return MapPRErrorCodeToResult(PR_GetError()); } return Success; }
Result VerifySignedData(const SignedDataWithSignature& sd, Input subjectPublicKeyInfo, void* pkcs11PinArg) { SECOidTag pubKeyAlg; SECOidTag digestAlg; switch (sd.algorithm) { case SignatureAlgorithm::ecdsa_with_sha512: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA512; break; case SignatureAlgorithm::ecdsa_with_sha384: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA384; break; case SignatureAlgorithm::ecdsa_with_sha256: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::ecdsa_with_sha1: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA1; break; case SignatureAlgorithm::rsa_pkcs1_with_sha512: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA512; break; case SignatureAlgorithm::rsa_pkcs1_with_sha384: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA384; break; case SignatureAlgorithm::rsa_pkcs1_with_sha256: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::rsa_pkcs1_with_sha1: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA1; break; case SignatureAlgorithm::dsa_with_sha256: pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::dsa_with_sha1: pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; digestAlg = SEC_OID_SHA1; break; default: PR_NOT_REACHED("unknown signature algorithm"); return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED; } Result rv; ScopedSECKeyPublicKey pubKey; rv = CheckPublicKeySize(subjectPublicKeyInfo, pubKey); if (rv != Success) { return rv; } // The static_cast is safe as long as the length of the data in sd.data can // fit in an int. Right now that length is stored as a uint16_t, so this // works. In the future this may change, hence the assertion. // See also bug 921585. static_assert(sizeof(decltype(sd.data.GetLength())) < sizeof(int), "sd.data.GetLength() must fit in an int"); SECItem dataSECItem(UnsafeMapInputToSECItem(sd.data)); SECItem signatureSECItem(UnsafeMapInputToSECItem(sd.signature)); SECStatus srv = VFY_VerifyDataDirect(dataSECItem.data, static_cast<int>(dataSECItem.len), pubKey.get(), &signatureSECItem, pubKeyAlg, digestAlg, nullptr, pkcs11PinArg); if (srv != SECSuccess) { return MapPRErrorCodeToResult(PR_GetError()); } return Success; }