diff --git a/doc/man-sections/pkcs11-options.rst b/doc/man-sections/pkcs11-options.rst index dfc27af333b..66a66a7ad5d 100644 --- a/doc/man-sections/pkcs11-options.rst +++ b/doc/man-sections/pkcs11-options.rst @@ -83,3 +83,15 @@ PKCS#11 / SmartCard options ``--verb`` option can be used BEFORE this option to produce debugging information. + +--pkcs11-pin pin + Specify the file with the PIN for the PKCS#11 token. + + Valid syntax: + :: + + pkcs11-pin file.txt + + If the PIN is specified from file, the file should contain only the PIN, + without any additional characters. + When ``--pkcs11-pin`` is not specified, the user will be prompted to enter the PIN. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 9b7bd424202..a2cdf3cd438 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -762,7 +762,7 @@ context_init_1(struct context *c) if (c->first_time) { int i; - pkcs11_initialize(true, c->options.pkcs11_pin_cache_period); + pkcs11_initialize(true, c->options.pkcs11_pin_cache_period, c->options.pkcs11_pin_file); for (i = 0; i < MAX_PARMS && c->options.pkcs11_providers[i] != NULL; i++) { pkcs11_addProvider( diff --git a/src/openvpn/options.c b/src/openvpn/options.c index b4b19f27c67..1b67273f39c 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -687,6 +687,7 @@ static const char usage_message[] = " cache until token is removed.\n" "--pkcs11-id-management : Acquire identity from management interface.\n" "--pkcs11-id serialized-id 'id' : Identity to use, get using standalone --show-pkcs11-ids\n" + "--pkcs11-pin file : File containing the PIN for the PKCS#11 token.\n" #endif /* ENABLE_PKCS11 */ "\n" "SSL Library information:\n" @@ -4256,6 +4257,14 @@ options_postprocess_filechecks(struct options *options) errs |= check_file_access_chroot(options->chroot_dir, CHKACC_FILE, options->tmp_dir, R_OK | W_OK | X_OK, "Temporary directory (--tmp-dir)"); +#ifdef ENABLE_PKCS11 + if (options->pkcs11_pin_file) + { + errs |= check_file_access(CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE, + options->pkcs11_pin_file, R_OK, "--pkcs11-pin"); + } +#endif + if (errs) { msg(M_USAGE, "Please correct these errors."); @@ -9174,6 +9183,18 @@ add_option(struct options *options, char *p[], bool is_inline, const char *file, VERIFY_PERMISSION(OPT_P_GENERAL); options->pkcs11_id_management = true; } + else if (streq(p[0], "pkcs11-pin") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + if (p[1]) + { + options->pkcs11_pin_file = p[1]; + } + else + { + options->pkcs11_pin_file = NULL; + } + } #endif /* ifdef ENABLE_PKCS11 */ else if (streq(p[0], "rmtun") && !p[1]) { diff --git a/src/openvpn/options.h b/src/openvpn/options.h index ae3156ac0be..d4a206dc580 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -629,6 +629,7 @@ struct options int pkcs11_pin_cache_period; const char *pkcs11_id; bool pkcs11_id_management; + const char *pkcs11_pin_file; #endif #ifdef ENABLE_CRYPTOAPI diff --git a/src/openvpn/pkcs11.c b/src/openvpn/pkcs11.c index cfcd3725a25..b504f73ad98 100644 --- a/src/openvpn/pkcs11.c +++ b/src/openvpn/pkcs11.c @@ -39,6 +39,15 @@ #include "console.h" #include "pkcs11_backend.h" + +struct pkcs11_context { + int nPINCachePeriod; + struct user_pass token_pass; + const char *pin_file; +}; + +static struct pkcs11_context pkcs11_ctx; /* GLOBAL */ + static time_t __mytime(void) { @@ -166,6 +175,44 @@ _pkcs11_openvpn_log(void *const global_data, unsigned flags, const char *const s msg(_pkcs11_msg_pkcs112openvpn(flags), "%s", Buffer); } + +static +PKCS11H_BOOL +pkcs11_password_setup( + const char *pkcs11_pin_file, + struct user_pass *token_pass + ) +{ + if (!token_pass) + { + return false; + } + if (pkcs11_pin_file) + { + msg(M_INFO, "pkcs11_password_setup - pkcs11_pin_file='%s'", pkcs11_pin_file); + } + else + { + /* If pin file is not provided, clear the token_pass and continue */ + CLEAR(token_pass); + return true; + } + token_pass->defined = false; + token_pass->nocache = true; + + if (!strlen(token_pass->password)) + { + get_user_pass( + token_pass, + pkcs11_pin_file, + UP_TYPE_PRIVATE_KEY, + GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY + ); + } + + return true; +} + static PKCS11H_BOOL _pkcs11_openvpn_token_prompt(void *const global_data, void *const user_data, const pkcs11h_token_id_t token, const unsigned retry) @@ -200,11 +247,15 @@ _pkcs11_openvpn_pin_prompt(void *const global_data, void *const user_data, const pkcs11h_token_id_t token, const unsigned retry, char *const pin, const size_t pin_max) { - struct user_pass token_pass; char prompt[1024]; - CLEAR(token_pass); + struct pkcs11_context *ctx = NULL; + + if (!global_data) + { + return false; + } + ctx = (struct pkcs11_context *)global_data; - (void)global_data; (void)user_data; (void)retry; @@ -212,19 +263,25 @@ _pkcs11_openvpn_pin_prompt(void *const global_data, void *const user_data, snprintf(prompt, sizeof(prompt), "%s token", token->label); - token_pass.defined = false; - token_pass.nocache = true; + ctx->token_pass.defined = false; + ctx->token_pass.nocache = true; - if (!get_user_pass(&token_pass, NULL, prompt, - GET_USER_PASS_MANAGEMENT | GET_USER_PASS_PASSWORD_ONLY - | GET_USER_PASS_NOFATAL)) + if ( + !strlen(ctx->token_pass.password) + && !get_user_pass( + &ctx->token_pass, + NULL, + prompt, + GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY|GET_USER_PASS_NOFATAL + ) + ) { return false; } else { - strncpynt(pin, token_pass.password, pin_max); - purge_user_pass(&token_pass, true); + strncpynt(pin, ctx->token_pass.password, pin_max); + purge_user_pass(&ctx->token_pass, true); if (strlen(pin) == 0) { @@ -238,12 +295,26 @@ _pkcs11_openvpn_pin_prompt(void *const global_data, void *const user_data, } bool -pkcs11_initialize(const bool protected_auth, const int nPINCachePeriod) +pkcs11_initialize(const bool protected_auth,const int nPINCachePeriod, + const char *pin_file) { CK_RV rv = CKR_FUNCTION_FAILED; + pkcs11_ctx.nPINCachePeriod = nPINCachePeriod; dmsg(D_PKCS11_DEBUG, "PKCS#11: pkcs11_initialize - entered"); + if (!pkcs11_password_setup(pin_file, &pkcs11_ctx.token_pass)) + { + msg(M_FATAL, "PKCS#11: Cannot initialize pkcs11 password"); + return false; + } + + if (!pkcs11_password_setup(pin_file, &pkcs11_ctx.token_pass)) + { + msg(M_FATAL, "PKCS#11: Cannot initialize pkcs11 password"); + return false; + } + if ((rv = pkcs11h_engine_setSystem(&s_pkcs11h_sys_engine)) != CKR_OK) { msg(M_FATAL, "PKCS#11: Cannot initialize system engine %ld-'%s'", rv, @@ -271,13 +342,13 @@ pkcs11_initialize(const bool protected_auth, const int nPINCachePeriod) goto cleanup; } - if ((rv = pkcs11h_setTokenPromptHook(_pkcs11_openvpn_token_prompt, NULL)) != CKR_OK) + if ((rv = pkcs11h_setTokenPromptHook(_pkcs11_openvpn_token_prompt, &pkcs11_ctx)) != CKR_OK) { msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv)); goto cleanup; } - if ((rv = pkcs11h_setPINPromptHook(_pkcs11_openvpn_pin_prompt, NULL)) != CKR_OK) + if ((rv = pkcs11h_setPINPromptHook(_pkcs11_openvpn_pin_prompt, &pkcs11_ctx)) != CKR_OK) { msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv)); goto cleanup; diff --git a/src/openvpn/pkcs11.h b/src/openvpn/pkcs11.h index 3ce37031308..544129641ca 100644 --- a/src/openvpn/pkcs11.h +++ b/src/openvpn/pkcs11.h @@ -27,7 +27,8 @@ #include "ssl_common.h" -bool pkcs11_initialize(const bool fProtectedAuthentication, const int nPINCachePeriod); +bool pkcs11_initialize(const bool fProtectedAuthentication, const int nPINCachePeriod, + const char *pin_file); void pkcs11_terminate(void); diff --git a/tests/unit_tests/openvpn/test_pkcs11.c b/tests/unit_tests/openvpn/test_pkcs11.c index 722f9b17d52..61bc03d1f87 100644 --- a/tests/unit_tests/openvpn/test_pkcs11.c +++ b/tests/unit_tests/openvpn/test_pkcs11.c @@ -320,7 +320,7 @@ setup_pkcs11(void **state) /* set default propq as we do in ssl_openssl.c */ EVP_set_default_properties(tls_libctx, "?provider!=ovpn.xkey"); #endif - pkcs11_initialize(true, 60); /* protected auth enabled, pin-cache = 60s */ + pkcs11_initialize(true, 60, NULL); /* protected auth enabled, pin-cache = 60s, pin_file = NULL */ pkcs11_addProvider(SOFTHSM2_MODULE_PATH, false, 0, false); return 0; }