Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
michael@0 | 3 | /* Copyright 2013 Mozilla Foundation |
michael@0 | 4 | * |
michael@0 | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
michael@0 | 6 | * you may not use this file except in compliance with the License. |
michael@0 | 7 | * You may obtain a copy of the License at |
michael@0 | 8 | * |
michael@0 | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
michael@0 | 10 | * |
michael@0 | 11 | * Unless required by applicable law or agreed to in writing, software |
michael@0 | 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
michael@0 | 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
michael@0 | 14 | * See the License for the specific language governing permissions and |
michael@0 | 15 | * limitations under the License. |
michael@0 | 16 | */ |
michael@0 | 17 | |
michael@0 | 18 | #include "pkix/pkix.h" |
michael@0 | 19 | |
michael@0 | 20 | #include <limits> |
michael@0 | 21 | #include <stdint.h> |
michael@0 | 22 | |
michael@0 | 23 | #include "cert.h" |
michael@0 | 24 | #include "cryptohi.h" |
michael@0 | 25 | #include "prerror.h" |
michael@0 | 26 | #include "secerr.h" |
michael@0 | 27 | |
michael@0 | 28 | namespace mozilla { namespace pkix { |
michael@0 | 29 | |
michael@0 | 30 | SECStatus |
michael@0 | 31 | VerifySignedData(const CERTSignedData* sd, const CERTCertificate* cert, |
michael@0 | 32 | void* pkcs11PinArg) |
michael@0 | 33 | { |
michael@0 | 34 | if (!sd || !sd->data.data || !sd->signatureAlgorithm.algorithm.data || |
michael@0 | 35 | !sd->signature.data || !cert) { |
michael@0 | 36 | PR_NOT_REACHED("invalid args to VerifySignedData"); |
michael@0 | 37 | PR_SetError(SEC_ERROR_INVALID_ARGS, 0); |
michael@0 | 38 | return SECFailure; |
michael@0 | 39 | } |
michael@0 | 40 | |
michael@0 | 41 | // See bug 921585. |
michael@0 | 42 | if (sd->data.len > static_cast<unsigned int>(std::numeric_limits<int>::max())) { |
michael@0 | 43 | PR_SetError(SEC_ERROR_INVALID_ARGS, 0); |
michael@0 | 44 | return SECFailure; |
michael@0 | 45 | } |
michael@0 | 46 | |
michael@0 | 47 | // convert sig->len from bit counts to byte count. |
michael@0 | 48 | SECItem sig = sd->signature; |
michael@0 | 49 | DER_ConvertBitString(&sig); |
michael@0 | 50 | |
michael@0 | 51 | // Use SECKEY_ExtractPublicKey instead of CERT_ExtractPublicKey because |
michael@0 | 52 | // CERT_ExtractPublicKey would try to do (EC)DSA parameter inheritance, using |
michael@0 | 53 | // the classic (wrong) NSS path building logic. We intentionally do not |
michael@0 | 54 | // support parameter inheritance. |
michael@0 | 55 | ScopedSECKEYPublicKey |
michael@0 | 56 | pubKey(SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo)); |
michael@0 | 57 | if (!pubKey) { |
michael@0 | 58 | return SECFailure; |
michael@0 | 59 | } |
michael@0 | 60 | |
michael@0 | 61 | SECOidTag hashAlg; |
michael@0 | 62 | if (VFY_VerifyDataWithAlgorithmID(sd->data.data, static_cast<int>(sd->data.len), |
michael@0 | 63 | pubKey.get(), &sig, &sd->signatureAlgorithm, |
michael@0 | 64 | &hashAlg, pkcs11PinArg) != SECSuccess) { |
michael@0 | 65 | return SECFailure; |
michael@0 | 66 | } |
michael@0 | 67 | |
michael@0 | 68 | // TODO: Ideally, we would do this check before we call |
michael@0 | 69 | // VFY_VerifyDataWithAlgorithmID. But, VFY_VerifyDataWithAlgorithmID gives us |
michael@0 | 70 | // the hash algorithm so it is more convenient to do things in this order. |
michael@0 | 71 | uint32_t policy; |
michael@0 | 72 | if (NSS_GetAlgorithmPolicy(hashAlg, &policy) != SECSuccess) { |
michael@0 | 73 | return SECFailure; |
michael@0 | 74 | } |
michael@0 | 75 | |
michael@0 | 76 | // XXX: I'm not sure why there isn't NSS_USE_ALG_IN_SSL_SIGNATURE, but there |
michael@0 | 77 | // isn't. Since we don't know the context in which we're being called, be as |
michael@0 | 78 | // strict as we can be given the NSS API that is available. |
michael@0 | 79 | static const uint32_t requiredPolicy = NSS_USE_ALG_IN_CERT_SIGNATURE | |
michael@0 | 80 | NSS_USE_ALG_IN_CMS_SIGNATURE; |
michael@0 | 81 | if ((policy & requiredPolicy) != requiredPolicy) { |
michael@0 | 82 | PR_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 0); |
michael@0 | 83 | return SECFailure; |
michael@0 | 84 | } |
michael@0 | 85 | |
michael@0 | 86 | return SECSuccess; |
michael@0 | 87 | } |
michael@0 | 88 | |
michael@0 | 89 | } } // namespace mozilla::pkix |