Mercurial > trustbridge
diff common/binverify.c @ 629:facb13c578f1
Add certificate pinning to verify_binary_win
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 23 Jun 2014 13:04:34 +0200 |
parents | 26a18e3c3db4 |
children | be30d50bc4f0 |
line wrap: on
line diff
--- a/common/binverify.c Fri Jun 20 14:29:05 2014 +0200 +++ b/common/binverify.c Mon Jun 23 13:04:34 2014 +0200 @@ -11,6 +11,12 @@ #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 @@ -25,11 +31,74 @@ #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; @@ -111,17 +180,29 @@ } /* Verify that the signature is actually valid */ - if(CryptMsgControl(hMsg, - 0, - CMSG_CTRL_VERIFY_SIGNATURE, - pSignerCertContext->pCertInfo)) + if(!CryptMsgControl(hMsg, + 0, + CMSG_CTRL_VERIFY_SIGNATURE, + pSignerCertContext->pCertInfo)) { - DEBUGPRINTF ("Verify signature succeeded. \n"); - /* TODO pinning*/ + 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; - } else { - ERRORPRINTF ("The signature was not verified. \n"); + goto done; + } + else + { + ERRORPRINTF ("Certificate mismatch. \n"); retval = VerifyInvalidSignature; + syslog_error_printf ("Software update embedded signature " + "created with wrong certificate."); goto done; }