michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* Copyright 2013 Mozilla Foundation michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: #include "pkix/pkix.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "cert.h" michael@0: #include "cryptohi.h" michael@0: #include "prerror.h" michael@0: #include "secerr.h" michael@0: michael@0: namespace mozilla { namespace pkix { michael@0: michael@0: SECStatus michael@0: VerifySignedData(const CERTSignedData* sd, const CERTCertificate* cert, michael@0: void* pkcs11PinArg) michael@0: { michael@0: if (!sd || !sd->data.data || !sd->signatureAlgorithm.algorithm.data || michael@0: !sd->signature.data || !cert) { michael@0: PR_NOT_REACHED("invalid args to VerifySignedData"); michael@0: PR_SetError(SEC_ERROR_INVALID_ARGS, 0); michael@0: return SECFailure; michael@0: } michael@0: michael@0: // See bug 921585. michael@0: if (sd->data.len > static_cast(std::numeric_limits::max())) { michael@0: PR_SetError(SEC_ERROR_INVALID_ARGS, 0); michael@0: return SECFailure; michael@0: } michael@0: michael@0: // convert sig->len from bit counts to byte count. michael@0: SECItem sig = sd->signature; michael@0: DER_ConvertBitString(&sig); michael@0: michael@0: // Use SECKEY_ExtractPublicKey instead of CERT_ExtractPublicKey because michael@0: // CERT_ExtractPublicKey would try to do (EC)DSA parameter inheritance, using michael@0: // the classic (wrong) NSS path building logic. We intentionally do not michael@0: // support parameter inheritance. michael@0: ScopedSECKEYPublicKey michael@0: pubKey(SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo)); michael@0: if (!pubKey) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: SECOidTag hashAlg; michael@0: if (VFY_VerifyDataWithAlgorithmID(sd->data.data, static_cast(sd->data.len), michael@0: pubKey.get(), &sig, &sd->signatureAlgorithm, michael@0: &hashAlg, pkcs11PinArg) != SECSuccess) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: // TODO: Ideally, we would do this check before we call michael@0: // VFY_VerifyDataWithAlgorithmID. But, VFY_VerifyDataWithAlgorithmID gives us michael@0: // the hash algorithm so it is more convenient to do things in this order. michael@0: uint32_t policy; michael@0: if (NSS_GetAlgorithmPolicy(hashAlg, &policy) != SECSuccess) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: // XXX: I'm not sure why there isn't NSS_USE_ALG_IN_SSL_SIGNATURE, but there michael@0: // isn't. Since we don't know the context in which we're being called, be as michael@0: // strict as we can be given the NSS API that is available. michael@0: static const uint32_t requiredPolicy = NSS_USE_ALG_IN_CERT_SIGNATURE | michael@0: NSS_USE_ALG_IN_CMS_SIGNATURE; michael@0: if ((policy & requiredPolicy) != requiredPolicy) { michael@0: PR_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 0); michael@0: return SECFailure; michael@0: } michael@0: michael@0: return SECSuccess; michael@0: } michael@0: michael@0: } } // namespace mozilla::pkix