LCOV - code coverage report
Current view: top level - security/manager/ssl - nsDataSignatureVerifier.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 144 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 11 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "nsDataSignatureVerifier.h"
       6             : 
       7             : #include "ScopedNSSTypes.h"
       8             : #include "SharedCertVerifier.h"
       9             : #include "cms.h"
      10             : #include "cryptohi.h"
      11             : #include "keyhi.h"
      12             : #include "mozilla/Base64.h"
      13             : #include "mozilla/Casting.h"
      14             : #include "mozilla/Unused.h"
      15             : #include "nsCOMPtr.h"
      16             : #include "nsNSSComponent.h"
      17             : #include "nsString.h"
      18             : #include "pkix/pkixnss.h"
      19             : #include "pkix/pkixtypes.h"
      20             : #include "secerr.h"
      21             : 
      22             : using namespace mozilla;
      23             : using namespace mozilla::pkix;
      24             : using namespace mozilla::psm;
      25             : 
      26             : SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
      27             : 
      28           0 : NS_IMPL_ISUPPORTS(nsDataSignatureVerifier, nsIDataSignatureVerifier)
      29             : 
      30             : const SEC_ASN1Template CERT_SignatureDataTemplate[] =
      31             : {
      32             :     { SEC_ASN1_SEQUENCE,
      33             :         0, nullptr, sizeof(CERTSignedData) },
      34             :     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
      35             :         offsetof(CERTSignedData,signatureAlgorithm),
      36             :         SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), },
      37             :     { SEC_ASN1_BIT_STRING,
      38             :         offsetof(CERTSignedData,signature), },
      39             :     { 0, }
      40             : };
      41             : 
      42           0 : nsDataSignatureVerifier::~nsDataSignatureVerifier()
      43             : {
      44           0 :   nsNSSShutDownPreventionLock locker;
      45           0 :   if (isAlreadyShutDown()) {
      46           0 :     return;
      47             :   }
      48             : 
      49           0 :   shutdown(ShutdownCalledFrom::Object);
      50           0 : }
      51             : 
      52             : NS_IMETHODIMP
      53           0 : nsDataSignatureVerifier::VerifyData(const nsACString& aData,
      54             :                                     const nsACString& aSignature,
      55             :                                     const nsACString& aPublicKey,
      56             :                                     bool* _retval)
      57             : {
      58           0 :   NS_ENSURE_ARG_POINTER(_retval);
      59             : 
      60           0 :   nsNSSShutDownPreventionLock locker;
      61           0 :   if (isAlreadyShutDown()) {
      62           0 :     return NS_ERROR_NOT_AVAILABLE;
      63             :   }
      64             : 
      65             :   // Allocate an arena to handle the majority of the allocations
      66           0 :   UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
      67           0 :   if (!arena) {
      68           0 :     return NS_ERROR_OUT_OF_MEMORY;
      69             :   }
      70             : 
      71             :   // Base 64 decode the key
      72             :   // For compatibility reasons we need to remove all whitespace first, since
      73             :   // Base64Decode() will not accept invalid characters.
      74           0 :   nsAutoCString b64KeyNoWhitespace(aPublicKey);
      75           0 :   b64KeyNoWhitespace.StripWhitespace();
      76           0 :   nsAutoCString key;
      77           0 :   nsresult rv = Base64Decode(b64KeyNoWhitespace, key);
      78           0 :   if (NS_FAILED(rv)) {
      79           0 :     return rv;
      80             :   }
      81             : 
      82             :   // Extract the public key from the data
      83             :   SECItem keyItem = {
      84             :     siBuffer,
      85           0 :     BitwiseCast<unsigned char*, const char*>(key.get()),
      86           0 :     key.Length(),
      87           0 :   };
      88             :   UniqueCERTSubjectPublicKeyInfo pki(
      89           0 :     SECKEY_DecodeDERSubjectPublicKeyInfo(&keyItem));
      90           0 :   if (!pki) {
      91           0 :     return NS_ERROR_FAILURE;
      92             :   }
      93             : 
      94           0 :   UniqueSECKEYPublicKey publicKey(SECKEY_ExtractPublicKey(pki.get()));
      95           0 :   if (!publicKey) {
      96           0 :     return NS_ERROR_FAILURE;
      97             :   }
      98             : 
      99             :   // Base 64 decode the signature
     100             :   // For compatibility reasons we need to remove all whitespace first, since
     101             :   // Base64Decode() will not accept invalid characters.
     102           0 :   nsAutoCString b64SignatureNoWhitespace(aSignature);
     103           0 :   b64SignatureNoWhitespace.StripWhitespace();
     104           0 :   nsAutoCString signature;
     105           0 :   rv = Base64Decode(b64SignatureNoWhitespace, signature);
     106           0 :   if (NS_FAILED(rv)) {
     107           0 :     return rv;
     108             :   }
     109             : 
     110             :   // Decode the signature and algorithm
     111             :   CERTSignedData sigData;
     112           0 :   PORT_Memset(&sigData, 0, sizeof(CERTSignedData));
     113             :   SECItem signatureItem = {
     114             :     siBuffer,
     115           0 :     BitwiseCast<unsigned char*, const char*>(signature.get()),
     116           0 :     signature.Length(),
     117           0 :   };
     118           0 :   SECStatus srv = SEC_QuickDERDecodeItem(arena.get(), &sigData,
     119             :                                          CERT_SignatureDataTemplate,
     120           0 :                                          &signatureItem);
     121           0 :   if (srv != SECSuccess) {
     122           0 :     return NS_ERROR_FAILURE;
     123             :   }
     124             : 
     125             :   // Perform the final verification
     126           0 :   DER_ConvertBitString(&(sigData.signature));
     127           0 :   srv = VFY_VerifyDataWithAlgorithmID(
     128             :     BitwiseCast<const unsigned char*, const char*>(
     129           0 :       PromiseFlatCString(aData).get()),
     130           0 :     aData.Length(), publicKey.get(), &(sigData.signature),
     131           0 :     &(sigData.signatureAlgorithm), nullptr, nullptr);
     132             : 
     133           0 :   *_retval = (srv == SECSuccess);
     134             : 
     135           0 :   return NS_OK;
     136             : }
     137             : 
     138             : namespace mozilla {
     139             : 
     140             : nsresult
     141           0 : VerifyCMSDetachedSignatureIncludingCertificate(
     142             :   const SECItem& buffer, const SECItem& detachedDigest,
     143             :   nsresult (*verifyCertificate)(CERTCertificate* cert, void* context,
     144             :                                 void* pinArg),
     145             :   void* verifyCertificateContext, void* pinArg,
     146             :   const nsNSSShutDownPreventionLock& /*proofOfLock*/)
     147             : {
     148             :   // XXX: missing pinArg is tolerated.
     149           0 :   if (NS_WARN_IF(!buffer.data && buffer.len > 0) ||
     150           0 :       NS_WARN_IF(!detachedDigest.data && detachedDigest.len > 0) ||
     151           0 :       (!verifyCertificate) ||
     152           0 :       NS_WARN_IF(!verifyCertificateContext)) {
     153           0 :     return NS_ERROR_INVALID_ARG;
     154             :   }
     155             : 
     156             :   UniqueNSSCMSMessage
     157             :     cmsMsg(NSS_CMSMessage_CreateFromDER(const_cast<SECItem*>(&buffer), nullptr,
     158             :                                         nullptr, nullptr, nullptr, nullptr,
     159           0 :                                         nullptr));
     160           0 :   if (!cmsMsg) {
     161           0 :     return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
     162             :   }
     163             : 
     164           0 :   if (!NSS_CMSMessage_IsSigned(cmsMsg.get())) {
     165           0 :     return NS_ERROR_CMS_VERIFY_NOT_SIGNED;
     166             :   }
     167             : 
     168           0 :   NSSCMSContentInfo* cinfo = NSS_CMSMessage_ContentLevel(cmsMsg.get(), 0);
     169           0 :   if (!cinfo) {
     170           0 :     return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO;
     171             :   }
     172             : 
     173             :   // signedData is non-owning
     174             :   NSSCMSSignedData* signedData =
     175           0 :     static_cast<NSSCMSSignedData*>(NSS_CMSContentInfo_GetContent(cinfo));
     176           0 :   if (!signedData) {
     177           0 :     return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO;
     178             :   }
     179             : 
     180             :   // Set digest value.
     181           0 :   if (NSS_CMSSignedData_SetDigestValue(signedData, SEC_OID_SHA1,
     182             :                                        const_cast<SECItem*>(&detachedDigest))) {
     183           0 :     return NS_ERROR_CMS_VERIFY_BAD_DIGEST;
     184             :   }
     185             : 
     186             :   // Parse the certificates into CERTCertificate objects held in memory so
     187             :   // verifyCertificate will be able to find them during path building.
     188           0 :   UniqueCERTCertList certs(CERT_NewCertList());
     189           0 :   if (!certs) {
     190           0 :     return NS_ERROR_OUT_OF_MEMORY;
     191             :   }
     192           0 :   if (signedData->rawCerts) {
     193           0 :     for (size_t i = 0; signedData->rawCerts[i]; ++i) {
     194             :       UniqueCERTCertificate
     195             :         cert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
     196           0 :                                      signedData->rawCerts[i], nullptr, false,
     197           0 :                                      true));
     198             :       // Skip certificates that fail to parse
     199           0 :       if (!cert) {
     200           0 :         continue;
     201             :       }
     202             : 
     203           0 :       if (CERT_AddCertToListTail(certs.get(), cert.get()) != SECSuccess) {
     204           0 :         return NS_ERROR_OUT_OF_MEMORY;
     205             :       }
     206             : 
     207           0 :       Unused << cert.release(); // Ownership transferred to the cert list.
     208             :     }
     209             :   }
     210             : 
     211             :   // Get the end-entity certificate.
     212           0 :   int numSigners = NSS_CMSSignedData_SignerInfoCount(signedData);
     213           0 :   if (NS_WARN_IF(numSigners != 1)) {
     214           0 :     return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
     215             :   }
     216             :   // signer is non-owning.
     217           0 :   NSSCMSSignerInfo* signer = NSS_CMSSignedData_GetSignerInfo(signedData, 0);
     218           0 :   if (NS_WARN_IF(!signer)) {
     219           0 :     return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
     220             :   }
     221             :   CERTCertificate* signerCert =
     222           0 :     NSS_CMSSignerInfo_GetSigningCertificate(signer, CERT_GetDefaultCertDB());
     223           0 :   if (!signerCert) {
     224           0 :     return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
     225             :   }
     226             : 
     227           0 :   nsresult rv = verifyCertificate(signerCert, verifyCertificateContext, pinArg);
     228           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     229           0 :     return rv;
     230             :   }
     231             : 
     232             :   // See NSS_CMSContentInfo_GetContentTypeOID, which isn't exported from NSS.
     233             :   SECOidData* contentTypeOidData =
     234           0 :     SECOID_FindOID(&signedData->contentInfo.contentType);
     235           0 :   if (!contentTypeOidData) {
     236           0 :     return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
     237             :   }
     238             : 
     239           0 :   return MapSECStatus(NSS_CMSSignerInfo_Verify(signer,
     240             :                          const_cast<SECItem*>(&detachedDigest),
     241           0 :                          &contentTypeOidData->oid));
     242             : }
     243             : 
     244             : } // namespace mozilla
     245             : 
     246             : namespace {
     247             : 
     248           0 : struct VerifyCertificateContext
     249             : {
     250             :   nsCOMPtr<nsIX509Cert> signingCert;
     251             :   UniqueCERTCertList builtChain;
     252             : };
     253             : 
     254             : static nsresult
     255           0 : VerifyCertificate(CERTCertificate* cert, void* voidContext, void* pinArg)
     256             : {
     257             :   // XXX: missing pinArg is tolerated
     258           0 :   if (NS_WARN_IF(!cert) || NS_WARN_IF(!voidContext)) {
     259           0 :     return NS_ERROR_INVALID_ARG;
     260             :   }
     261             : 
     262             :   VerifyCertificateContext* context =
     263           0 :     static_cast<VerifyCertificateContext*>(voidContext);
     264             : 
     265           0 :   nsCOMPtr<nsIX509Cert> xpcomCert(nsNSSCertificate::Create(cert));
     266           0 :   if (!xpcomCert) {
     267           0 :     return NS_ERROR_OUT_OF_MEMORY;
     268             :   }
     269             : 
     270           0 :   context->signingCert = xpcomCert;
     271             : 
     272           0 :   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
     273           0 :   NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
     274             : 
     275             :   mozilla::pkix::Result result =
     276           0 :     certVerifier->VerifyCert(cert,
     277             :                              certificateUsageObjectSigner,
     278             :                              Now(), pinArg,
     279             :                              nullptr, // hostname
     280           0 :                              context->builtChain);
     281           0 :   if (result != Success) {
     282           0 :     return GetXPCOMFromNSSError(MapResultToPRErrorCode(result));
     283             :   }
     284             : 
     285           0 :   return NS_OK;
     286             : }
     287             : 
     288             : } // namespace
     289             : 
     290             : NS_IMETHODIMP
     291           0 : nsDataSignatureVerifier::VerifySignature(const nsACString& aRSABuf,
     292             :                                          const nsACString& aPlaintext,
     293             :                                          int32_t* aErrorCode,
     294             :                                          nsIX509Cert** aSigningCert)
     295             : {
     296           0 :   if (!aErrorCode || !aSigningCert) {
     297           0 :     return NS_ERROR_INVALID_ARG;
     298             :   }
     299             : 
     300           0 :   nsNSSShutDownPreventionLock locker;
     301           0 :   if (isAlreadyShutDown()) {
     302           0 :     return NS_ERROR_NOT_AVAILABLE;
     303             :   }
     304             : 
     305           0 :   *aErrorCode = VERIFY_ERROR_OTHER;
     306           0 :   *aSigningCert = nullptr;
     307             : 
     308           0 :   Digest digest;
     309           0 :   nsresult rv = digest.DigestBuf(
     310             :     SEC_OID_SHA1,
     311             :     BitwiseCast<const uint8_t*, const char*>(aPlaintext.BeginReading()),
     312           0 :     aPlaintext.Length());
     313           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     314           0 :     return rv;
     315             :   }
     316             : 
     317             :   SECItem buffer = {
     318             :     siBuffer,
     319           0 :     BitwiseCast<unsigned char*, const char*>(aRSABuf.BeginReading()),
     320           0 :     aRSABuf.Length(),
     321           0 :   };
     322             : 
     323           0 :   VerifyCertificateContext context;
     324             :   // XXX: pinArg is missing
     325           0 :   rv = VerifyCMSDetachedSignatureIncludingCertificate(buffer, digest.get(),
     326             :                                                       VerifyCertificate,
     327           0 :                                                       &context, nullptr, locker);
     328           0 :   if (NS_SUCCEEDED(rv)) {
     329           0 :     *aErrorCode = VERIFY_OK;
     330           0 :   } else if (NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_SECURITY) {
     331           0 :     if (rv == GetXPCOMFromNSSError(SEC_ERROR_UNKNOWN_ISSUER)) {
     332           0 :       *aErrorCode = VERIFY_ERROR_UNKNOWN_ISSUER;
     333             :     } else {
     334           0 :       *aErrorCode = VERIFY_ERROR_OTHER;
     335             :     }
     336           0 :     rv = NS_OK;
     337             :   }
     338           0 :   if (rv == NS_OK) {
     339           0 :     context.signingCert.forget(aSigningCert);
     340             :   }
     341             : 
     342           0 :   return rv;
     343             : }

Generated by: LCOV version 1.13