view common/binverify.c @ 648:e41a2537b84d

Implement root installation We now iterate over all users that do not obviously have their login shell disabled and look for NSS directories in their home directory, dropping our privileges to do so.
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 25 Jun 2014 12:44:47 +0200
parents be30d50bc4f0
children 2798f1869eee
line wrap: on
line source
/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
 * Software engineering by Intevation GmbH
 *
 * This file is Free Software under the GNU GPL (v>=2)
 * and comes with ABSOLUTELY NO WARRANTY!
 * See LICENSE.txt for details.
 */

#include "binverify.h"

#include "strhelp.h"
#include "logging.h"

#ifdef RELEASE_BUILD
#include "pubkey-release.h"
#else
#include "pubkey-test.h"
#endif

bin_verify_result
verify_binary(const char *filename, size_t name_len) {
#ifdef WIN32
  return verify_binary_win(filename, name_len);
#else
  /* TODO */
  if (filename && name_len)
    return VerifyValid;
  return VerifyUnknownError;
#endif
}

#ifdef WIN32

#include <polarssl/x509_crt.h>

#include <windows.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <stdio.h>


/** @brief Check if the certificate @a pCCertContext is pinned
  *
  * Compares the certificate's binary data (public key and attributes)
  * with each other to validate that the certificate pCCertContext has
  * exactly the same data as the builtin public certificate.
  *
  * @param[in] pCCertContext pointer to the certificate to check
  *
  * @returns true if the certificate matches, false otherwise.
  */
static bool
check_certificate (PCCERT_CONTEXT pCCertContext)
{
  x509_crt codesign_cert;
  int ret = 0;
  DWORD dwI = 0;
  bool retval = false;

  if (pCCertContext == NULL)
    {
      ERRORPRINTF ("Invalid call to check_certificate");
      return false;
    }

  x509_crt_init(&codesign_cert);

  /* Parse the pinned certificate */
  ret = x509_crt_parse(&codesign_cert,
                       public_key_codesign_pem,
                       public_key_codesign_pem_size);
  if (ret != 0)
    {
      ERRORPRINTF ("x509_crt_parse failed with -0x%04x\n\n", -ret);
      goto done;
    }

  if (codesign_cert.raw.len != pCCertContext->cbCertEncoded ||
      codesign_cert.raw.len <= 0)
    {
      ERRORPRINTF ("Certificate size mismatch");
      goto done;
    }

  /* Check that the certificate is exactly the same as the pinned one */
  for (dwI = 0; dwI < pCCertContext->cbCertEncoded; dwI++)
    {
      if (pCCertContext->pbCertEncoded[dwI] != codesign_cert.raw.p[dwI])
        {
          ERRORPRINTF ("Certificate content mismatch");
          goto done;
        }
    }

  retval = true;

done:
  x509_crt_free(&codesign_cert);
  return retval;
}

bin_verify_result
verify_binary_win(const char *filename, size_t name_len) {
  bin_verify_result retval = VerifyUnknownError;
  WCHAR *filenameW = NULL;
  BOOL result = FALSE;
  DWORD dwEncoding = 0,
        dwContentType = 0,
        dwFormatType = 0,
        dwSignerInfoSize = 0;
  HCERTSTORE hStore = NULL;
  HCRYPTMSG hMsg = NULL;
  PCERT_INFO pSignerCert = NULL;
  PCCERT_CONTEXT pSignerCertContext = NULL;

  if (!filename || name_len > MAX_PATH || strlen(filename) != name_len)
    {
      ERRORPRINTF ("Invalid parameters\n");
      return VerifyUnknownError;
    }

  filenameW = utf8_to_wchar(filename, name_len);

  result = CryptQueryObject (CERT_QUERY_OBJECT_FILE,
                             filenameW,
                             CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
                             CERT_QUERY_FORMAT_FLAG_BINARY,
                             0,
                             &dwEncoding,
                             &dwContentType,
                             &dwFormatType,
                             &hStore,
                             &hMsg,
                             NULL);

  if (!result || !hMsg)
    {
      PRINTLASTERROR ("Failed to query crypto object");
      retval = VerifyReadFailed;
      goto done;
    }

  /* Get the cert info so that we can look up the signer in the store later */
  if (CryptMsgGetParam(hMsg,
                       CMSG_SIGNER_CERT_INFO_PARAM,
                       0,
                       NULL,
                       &dwSignerInfoSize) && dwSignerInfoSize > 0)
    {
      pSignerCert = xmalloc (dwSignerInfoSize);
    }
  else
    {
      ERRORPRINTF ("Failed to get signer cert size.");
      retval = VerifyUnknownError;
      goto done;
    }

  if (!(CryptMsgGetParam(hMsg,
                         CMSG_SIGNER_CERT_INFO_PARAM,
                         0,
                         pSignerCert,
                         &dwSignerInfoSize)))
    {
      ERRORPRINTF ("Failed to get signer cert.");
      retval = VerifyUnknownError;
      goto done;
    }

  pSignerCertContext = CertGetSubjectCertificateFromStore(
          hStore,
          PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
          pSignerCert);

  if (!pSignerCertContext)
    {
      ERRORPRINTF ("Failed to find signer cert in store.");
      retval = VerifyUnknownError;
      goto done;
    }

  /* Verify that the signature is actually valid */
  if(!CryptMsgControl(hMsg,
                      0,
                      CMSG_CTRL_VERIFY_SIGNATURE,
                      pSignerCertContext->pCertInfo))
    {
      ERRORPRINTF ("The signature is invalid. \n");
      retval = VerifyInvalidSignature;
      syslog_error_printf ("Software update embedded signature is invalid.");
      goto done;
    }

  if(check_certificate(pSignerCertContext))
    {
      DEBUGPRINTF ("Valid signature with pinned certificate.");
      retval = VerifyValid;
      goto done;
    }
  else
    {
      ERRORPRINTF ("Certificate mismatch. \n");
      retval = VerifyInvalidCertificate;
      syslog_error_printf ("Software update embedded signature "
                           "created with wrong certificate.");
      goto done;
    }

done:
  xfree(filenameW);
  xfree(pSignerCert);

  if(pSignerCertContext)
    {
      CertFreeCertificateContext(pSignerCertContext);
    }
  if (hStore)
    {
      CertCloseStore(hStore, 0);
    }
  if (hMsg)
    {
      CryptMsgClose(hMsg);
    }
  return retval;
}
#endif /* WIN32 */

http://wald.intevation.org/projects/trustbridge/