Mercurial > trustbridge
view common/binverify.c @ 831:747a48996c1f
(Issue13) Precompile uninstaller
Create-dist-packge now creates a temporary installer that only
writes the uninstaller. Then it excutes this installer (using wine)
to create the uninstaller. That uninstaller is then packaged
normaly and packaged instead of the written uninstaller.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Thu, 24 Jul 2014 15:59:00 +0200 |
parents | 44fa5de02b52 |
children | 698b6a9bd75e |
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) { if (!filename || !name_len) return VerifyUnknownError; #ifdef WIN32 return verify_binary_win(filename, name_len); #else return verify_binary_linux(filename, name_len); #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; } #else /* WIN32 */ #include "listutil.h" #pragma GCC diagnostic ignored "-Wconversion" /* Polarssl mh.h contains a conversion which gcc warns about */ #include <polarssl/pk.h> #include <polarssl/base64.h> #include <polarssl/sha256.h> #include <polarssl/error.h> #include <polarssl/x509_crt.h> #pragma GCC diagnostic pop bin_verify_result verify_binary_linux(const char *filename, size_t name_len) { int ret = -1; const size_t sig_b64_size = TRUSTBRIDGE_RSA_KEY_SIZE / 8 * 4 / 3; char *data = NULL, signature_b64[sig_b64_size + 1]; size_t data_size = 0, sig_size = TRUSTBRIDGE_RSA_KEY_SIZE / 8; unsigned char signature[sig_size], hash[32]; bin_verify_result retval = VerifyUnknownError; x509_crt codesign_cert; if (strnlen(filename, name_len + 1) != name_len || name_len == 0) { ERRORPRINTF ("Invalid call to verify_binary_linux\n"); return VerifyUnknownError; } ret = read_file(filename, &data, &data_size, MAX_VALID_BIN_SIZE); if (ret != 0) { ERRORPRINTF ("Read file failed with error: %i\n", ret); return VerifyReadFailed; } /* Fetch the signature from the end of data */ if (data_size < sig_b64_size + 5) { ERRORPRINTF ("File to small to contain a signature.\n"); retval = VerifyInvalidSignature; goto done; } if (data[data_size - sig_b64_size - 2] != ':' || data[data_size - sig_b64_size - 3] != 'S' || data[data_size - sig_b64_size - 4] != '\n'|| data[data_size - sig_b64_size - 5] != '\r') { ERRORPRINTF ("Failed to find valid signature line.\n"); retval = VerifyInvalidSignature; goto done; } strncpy(signature_b64, data + (data_size - sig_b64_size - 1), sig_b64_size); signature_b64[sig_b64_size] = '\0'; ret = base64_decode(signature, &sig_size, (unsigned char *)signature_b64, sig_b64_size); if (ret != 0 || sig_size != TRUSTBRIDGE_RSA_KEY_SIZE / 8) { ERRORPRINTF ("Base 64 decode failed with error: %i\n", ret); goto done; } /* Hash is calculated over the data without the signature at the end. */ sha256((unsigned char *)data, data_size - sig_b64_size - 5, hash, 0); 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) { char errbuf[1020]; polarssl_strerror(ret, errbuf, 1020); errbuf[1019] = '\0'; /* Just to be sure */ ERRORPRINTF ("x509_crt_parse failed with -0x%04x\n%s\n", -ret, errbuf); x509_crt_free(&codesign_cert); return VerifyUnknownError; } ret = pk_verify(&codesign_cert.pk, POLARSSL_MD_SHA256, hash, 0, signature, sig_size); if (ret != 0) { char errbuf[1020]; polarssl_strerror(ret, errbuf, 1020); errbuf[1019] = '\0'; /* Just to be sure */ ERRORPRINTF ("pk_verify failed with -0x%04x\n %s\n", -ret, errbuf); x509_crt_free(&codesign_cert); retval = VerifyInvalidSignature; goto done; } x509_crt_free(&codesign_cert); retval = VerifyValid; done: xfree (data); return retval; } #endif /* WIN32 */