aheinecke@25: /** @brief Main entry point for the cinst process. aheinecke@25: * aheinecke@25: * The cinst process may or may not be run with elevated aheinecke@25: * privileges. When run with elevated privileges this aheinecke@25: * process will modify system wide certificate stores. aheinecke@25: * Otherwise only the users certificate stores are modified. aheinecke@25: * aheinecke@59: * It expects a certificatelist on stdin enclosed in a aheinecke@59: * -----BEGIN CERTIFICATE LIST----- aheinecke@59: * ... aheinecke@59: * -----END CERTIFICATE LIST----- aheinecke@59: * aheinecke@59: * Followed by additional instruction lines of: aheinecke@59: * I: aheinecke@59: * R: aheinecke@59: * aheinecke@59: * It will only execute the instructions if the aheinecke@59: * I and R instructions are also part of the signed aheinecke@59: * certificate list. The signature is validated with the aheinecke@59: * built in key. aheinecke@59: * aheinecke@59: * The special instruction "UNINSTALL" will cause the installer aheinecke@59: * to remove all certificates (Even those marked with I) that aheinecke@59: * are part of the list to be removed. aheinecke@25: * aheinecke@25: **/ aheinecke@25: #include aheinecke@64: #include aheinecke@59: #include aheinecke@59: #include aheinecke@59: aheinecke@68: #include aheinecke@68: aheinecke@59: #include "strhelp.h" aheinecke@59: #include "listutil.h" aheinecke@60: #include "errorcodes.h" aheinecke@59: aheinecke@68: #ifdef WIN32 aheinecke@68: #include aheinecke@68: #include aheinecke@68: #endif aheinecke@68: aheinecke@68: /* The certificate list + instructions may only be so long as aheinecke@68: * twice the accepted certificatelist size */ aheinecke@68: #define MAX_INPUT_SIZE MAX_LINE_LENGTH * MAX_LINES * 2 aheinecke@68: aheinecke@59: /* @brief Read stdin into data structures. aheinecke@59: * aheinecke@59: * Reads from stdin and sorts the input into the respective aheinecke@59: * variables. The pointers returned need to be freed by the caller. aheinecke@59: * Terminates in OOM conditions. aheinecke@59: * aheinecke@60: * The caller needs to free the memory allocated by this function aheinecke@60: * even when an error is returned. aheinecke@60: * aheinecke@60: * @returns: 0 on success. An error code otherwise. aheinecke@59: */ aheinecke@64: int readInput(char **certificate_list, char ***to_install, aheinecke@59: char ***to_remove) aheinecke@59: { aheinecke@59: int lines_read = 0; aheinecke@59: int readingList = 0; aheinecke@91: size_t list_size = 0; aheinecke@59: char buf[MAX_LINE_LENGTH + 1]; aheinecke@59: aheinecke@90: if (*certificate_list || *to_install || *to_remove) { aheinecke@90: printf("Error invalid parameters\n"); aheinecke@90: return -1; aheinecke@90: } aheinecke@90: aheinecke@59: while (fgets(buf, MAX_LINE_LENGTH + 1, stdin)) { aheinecke@60: size_t len = strlen(buf); /* fgets ensures buf is terminated */ aheinecke@91: if (len < 2) { aheinecke@91: printf("Line to short.\n"); aheinecke@91: return ERR_INVALID_INPUT; aheinecke@91: } aheinecke@59: if (lines_read ++ > MAX_LINES) { aheinecke@59: printf("Too many lines\n"); aheinecke@60: return ERR_TOO_MUCH_INPUT; aheinecke@59: } aheinecke@64: if (strcmp("-----BEGIN CERTIFICATE LIST-----\r\n", buf) == 0){ aheinecke@59: readingList = 1; aheinecke@59: continue; aheinecke@59: } aheinecke@64: if (strcmp("-----END CERTIFICATE LIST-----\r\n", buf) == 0){ aheinecke@59: readingList = 0; aheinecke@59: continue; aheinecke@59: } aheinecke@59: if (readingList) { aheinecke@91: str_append_str(certificate_list, &list_size, buf, len); aheinecke@59: continue; aheinecke@59: } aheinecke@59: if (*buf == 'I') { aheinecke@68: /* Remove leading I: and trailing \r\n */ wilde@116: strv_append(to_install, buf+2, len - 4); aheinecke@59: continue; aheinecke@59: } aheinecke@59: if (*buf == 'R') { aheinecke@68: /* Remove leading R: and trailing \r\n */ wilde@116: strv_append(to_remove, buf+2, len - 4); aheinecke@59: continue; aheinecke@59: } aheinecke@59: if (strcmp("UNINSTALL", buf) == 0) { aheinecke@68: /* Remove trailing \r\n */ wilde@116: strv_append(to_remove, buf, len - 2); aheinecke@59: } aheinecke@59: } aheinecke@59: aheinecke@60: return 0; aheinecke@59: } aheinecke@65: /* aheinecke@64: int validate_instructions(const char *certificate_list, aheinecke@65: const size_t list_len, aheinecke@64: const char **to_install, aheinecke@64: const char **to_remove) aheinecke@64: { aheinecke@65: TODO aheinecke@65: (void *) certificate_list; aheinecke@65: (void **) to_install; aheinecke@65: (void **) to_remove; aheinecke@65: (void) list_len; aheinecke@65: aheinecke@64: return 0; aheinecke@64: } aheinecke@65: */ aheinecke@68: aheinecke@68: #ifdef WIN32 aheinecke@68: /** @brief Install certificates into Windows store aheinecke@68: * aheinecke@68: * @param [in] to_install NULL terminated array of base64 encoded certificates. aheinecke@68: * @param [in] user_store set to True if the certificates shoudl be installed aheinecke@68: * only for the current user. O for system wide installation. aheinecke@68: * @returns 0 on success an errorcode otherwise. aheinecke@68: */ aheinecke@68: int install_certificates_win(const char **to_install, int user_store) aheinecke@68: { aheinecke@68: int i = 0; aheinecke@68: HCERTSTORE hStore = NULL; aheinecke@68: aheinecke@68: if (!user_store) { aheinecke@68: // Access user store aheinecke@68: hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, aheinecke@68: 0, CERT_SYSTEM_STORE_CURRENT_USER, L"Root"); aheinecke@68: } else { aheinecke@68: // Access machine store aheinecke@68: hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, aheinecke@68: 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"Root"); aheinecke@68: } aheinecke@68: aheinecke@68: if (!hStore) { aheinecke@68: return ERR_STORE_ACCESS_DENIED; aheinecke@68: } aheinecke@68: aheinecke@68: while (to_install[i]) { aheinecke@68: size_t needed_len = 0; aheinecke@68: size_t cert_len = strnlen(to_install[i], MAX_LINE_LENGTH); aheinecke@68: int ret = -1; aheinecke@68: unsigned char *buf; aheinecke@68: /* Check the needed size for the buffer */ aheinecke@68: ret = base64_decode(NULL, &needed_len, aheinecke@68: (unsigned char *)to_install[i], cert_len); aheinecke@68: aheinecke@68: if (ret != 0 && ret != POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL) { aheinecke@68: return ERR_INVALID_INSTRUCTIONS; aheinecke@68: } aheinecke@68: aheinecke@68: buf = xmalloc(needed_len); aheinecke@68: memset (buf, 0, needed_len); aheinecke@68: aheinecke@68: ret = base64_decode(buf, &needed_len, aheinecke@68: (unsigned char *)to_install[i], cert_len); aheinecke@68: aheinecke@68: if (ret != 0) { aheinecke@68: return ERR_INVALID_INSTRUCTIONS; aheinecke@68: } aheinecke@68: aheinecke@68: ret = CertAddEncodedCTLToStore (hStore, aheinecke@68: X509_ASN_ENCODING, aheinecke@68: (PBYTE)buf, aheinecke@68: needed_len, aheinecke@68: CERT_STORE_ADD_ALWAYS, aheinecke@68: NULL); aheinecke@68: aheinecke@68: if (ret != 0) { aheinecke@68: printf("Failed to add certificate\n"); aheinecke@68: free(buf); aheinecke@68: return ret; aheinecke@68: } aheinecke@68: free(buf); aheinecke@68: } aheinecke@68: if(hStore) { aheinecke@68: CertCloseStore(hStore, 0); aheinecke@68: } aheinecke@68: return 0; aheinecke@68: } aheinecke@68: #endif aheinecke@68: andre@26: int main() { aheinecke@59: char **to_install = NULL; aheinecke@59: char **to_remove = NULL; aheinecke@64: char *certificate_list = NULL; aheinecke@65: size_t list_len = 0; aheinecke@59: int ret = -1; aheinecke@68: /* aheinecke@68: i = 0 , aheinecke@68: uninstall = 0; aheinecke@68: */ aheinecke@64: ret = readInput(&certificate_list, &to_install, &to_remove); aheinecke@60: aheinecke@60: if (ret != 0) { aheinecke@60: return ret; aheinecke@60: } aheinecke@60: aheinecke@64: if (!certificate_list) { aheinecke@60: return ERR_INVALID_INPUT_NO_LIST; aheinecke@60: } aheinecke@59: aheinecke@65: list_len = strnlen(certificate_list, MAX_INPUT_SIZE); aheinecke@59: aheinecke@65: ret = verify_list(certificate_list, list_len); aheinecke@64: aheinecke@64: if (ret != 0) { aheinecke@64: return ERR_INVALID_SIGNATURE; aheinecke@64: } aheinecke@64: aheinecke@64: if (!strv_length(to_install) && !strv_length(to_remove)) { aheinecke@64: return ERR_NO_INSTRUCTIONS; aheinecke@64: } aheinecke@64: aheinecke@68: aheinecke@68: /* Check that the instructions are ok to execute aheinecke@65: ret = validate_instructions(certificate_list, list_len, to_install, aheinecke@65: to_remove); aheinecke@64: if (ret != 0) { aheinecke@64: return ERR_INVALID_INSTRUCTIONS; aheinecke@64: } aheinecke@68: aheinecke@68: if (to_remove) { aheinecke@68: for (i=0; to_remove[i]; i++) { aheinecke@68: if (strncmp("UNINSTALL", to_remove[i], MAX_LINE_LENGTH)) { aheinecke@68: uninstall = 1; aheinecke@68: break; aheinecke@68: } aheinecke@68: } aheinecke@68: } aheinecke@68: aheinecke@68: if (uninstall) { aheinecke@68: aheinecke@68: } aheinecke@68: */ aheinecke@68: aheinecke@68: #ifdef WIN32 aheinecke@68: install_certificates_win((const char**) to_install, 1); aheinecke@68: //remove_certificates_win((const char**) to_remove, 1); aheinecke@68: #endif aheinecke@68: aheinecke@64: /* Make valgrind happy */ wilde@116: strv_free(to_install); wilde@116: strv_free(to_remove); aheinecke@68: free(certificate_list); aheinecke@59: aheinecke@25: return 0; aheinecke@25: }